iOS: NSTimer使用小记
1. NSRunLoopCommonModes和Timer
当使用NSTimer的scheduledTimerWithTimeInterval方法时。事实上此时Timer会被加入到当前线程的Run Loop中,且模式是默认的NSDefaultRunLoopMode。而如果当前线程就是主线程,也就是UI线程时,某些UI事件,比如UIScrollView的拖动操作,会将Run Loop切换成NSEventTrackingRunLoopMode模式,在这个过程中,默认的NSDefaultRunLoopMode模式中注册的事件是不会被执行的。也就是说,此时使用scheduledTimerWithTimeInterval添加到Run
Loop中的Timer就不会执行。
所以为了设置一个不被UI干扰的Timer,我们需要手动创建一个Timer,然后使用NSRunLoop的addTimer:forMode:方法来把Timer按照指定模式加入到Run Loop中。这里使用的模式是:NSRunLoopCommonModes,这个模式等效于NSDefaultRunLoopMode和NSEventTrackingRunLoopMode的结合。(参考Apple文档)
参考代码:
- (void)viewDidLoad
{
[super viewDidLoad];
NSLog(@"主线程 %@",
[NSThread currentThread]);
//创建Timer
NSTimer *timer
= [NSTimer timerWithTimeInterval:2.0 target:self selector:@selector(timer_callback) userInfo:nil repeats:YES];
//使用NSRunLoopCommonModes模式,把timer加入到当前Run
Loop中。
[[NSRunLoop currentRunLoop] addTimer:timer forMode:NSRunLoopCommonModes];
}
//timer的回调方法
- (void)timer_callback
{
NSLog(@"Timer
%@", [NSThread currentThread]);
}
输出:
主线程 <NSThread: 0x71501e0>{name = (null), num = 1}
Timer <NSThread: 0x71501e0>{name = (null), num = 1}
Timer <NSThread: 0x71501e0>{name = (null), num = 1}
Timer <NSThread: 0x71501e0>{name = (null), num = 1}
2. NSThread和Timer
上面讲的NSRunLoopCommonModes和Timer中有一个问题,这个Timer本质上是在当前线程的Run Loop中循环执行的,因此Timer的回调方法不是在另一个线程的。那么怎样在真正的多线程环境下运行一个Timer呢?
可以先试试NSThread。同上,我们还是会把Timer加到Run Loop中,只不过这个是在另一个线程中,因此我们需要手动执行Run Loop(通过NSRunLoop的run方法),同时注意在新的线程执行中加入@autoreleasepool。
完整代码如下:
- (void)viewDidLoad
{
[super viewDidLoad];
NSLog(@"主线程 %@",
[NSThread currentThread]);
//创建并执行新的线程
NSThread *thread
= [[NSThread alloc] initWithTarget:self selector:@selector(newThread) object:nil];
[thread start];
}
- (void)newThread
{
@autoreleasepool
{
//在当前Run
Loop中添加timer,模式是默认的NSDefaultRunLoopMode
[NSTimer scheduledTimerWithTimeInterval:2.0 target:self selector:@selector(timer_callback) userInfo:nil repeats:YES];
//开始执行新线程的Run
Loop
[[NSRunLoop currentRunLoop] run];
}
}
//timer的回调方法
- (void)timer_callback
{
NSLog(@"Timer
%@", [NSThread currentThread]);
}
输出:
主线程 <NSThread: 0x7118800>{name = (null), num = 1}
Timer <NSThread: 0x715c2e0>{name = (null), num = 3}
Timer <NSThread: 0x715c2e0>{name = (null), num = 3}
Timer <NSThread: 0x715c2e0>{name = (null), num = 3}
3. GCD中的Timer
GCD中的Timer应该是最灵活的,而且是多线程的。GCD中的Timer是靠Dispatch Source来实现的。
因此先需要声明一个dispatch_source_t本地变量:
@interface ViewController ()
{
dispatch_source_t _timer;
}
接着通过dispatch_source_create函数来创建一个专门的Dispatch Source,接着通过dispatch_source_set_timer函数来设置Timer的参数,注意这里的时间参数有些蛋疼。
开始时间的类型是dispatch_time_t,最好用dispatch_time或者dispatch_walltime函数来创建dispatch_time_t对象。如果需要Timer立即执行,可以传入dispatch_time(DISPATCH_TIME_NOW, 0)。
internal和leeway参数分别表示Timer的间隔时间和精度。类型都是uint64_t。间隔时间的单位竟然是纳秒。可以借助预定义的NSEC_PER_SEC宏,比如如果间隔时间是两秒的话,那interval参数就是:2 * NSEC_PER_SEC。
leeway就是精度参数,代表系统可以延时的时间间隔,最高精度当然就传0。
然后通过dispatch_source_set_event_handler函数来设置Dispatch Source的事件回调,这里当然是使用Block了。
最后所有dispatch_source_t创建后默认都是暂停状态的,所以必须通过dispatch_resume函数来开始事件监听。这里就代表着开始Timer。
完整代码:
NSLog(@"主线程 %@",
[NSThread currentThread]);
//间隔还是2秒
uint64_t interval = 2 * NSEC_PER_SEC;
//创建一个专门执行timer回调的GCD队列
dispatch_queue_t queue = dispatch_queue_create("my
queue", 0);
//创建Timer
_timer = dispatch_source_create(DISPATCH_SOURCE_TYPE_TIMER, 0, 0,
queue);
//使用dispatch_source_set_timer函数设置timer参数
dispatch_source_set_timer(_timer, dispatch_time(DISPATCH_TIME_NOW, 0),
interval, 0);
//设置回调
dispatch_source_set_event_handler(_timer,
^()
{
NSLog(@"Timer
%@", [NSThread currentThread]);
});
//dispatch_source默认是Suspended状态,通过dispatch_resume函数开始它
dispatch_resume(_timer);
输出:
主线程 <NSThread: 0x711fab0>{name = (null), num = 1}
Timer <NSThread: 0x713a380>{name = (null), num = 3}
Timer <NSThread: 0x713a380>{name = (null), num = 3}
Timer <NSThread: 0x713a380>{name = (null), num = 3}
iOS: NSTimer使用小记的更多相关文章
- iOS NSTimer使用详解 开启、关闭、移除
定时器定时器详解ios定时器关闭定时器NSTimer 一,要使用一个定时器首先要定义一个定时器: @property (strong, nonatomic) NSTimer *myTimer;//定时 ...
- 【转】IOS NSTimer 定时器用法总结
原文网址:http://my.oschina.net/u/2340880/blog/398598 NSTimer在IOS开发中会经常用到,尤其是小型游戏,然而对于初学者时常会注意不到其中的内存释放问题 ...
- IOS NSTimer 定时器用法总结
NSTimer在IOS开发中会经常用到,尤其是小型游戏,然而对于初学者时常会注意不到其中的内存释放问题,将其基本用法总结如下: 一.初始化方法:有五种初始化方法,分别是 + (NSTimer *)ti ...
- ios - NSTimer中target的self是强引用问题
当控制器ViewController跳转进入控制器OneViewController中的时候开启定时器,让定时器每隔一段时间打印一次,当OneViewController dismiss的时候,控制器 ...
- iOS 推送小记
ios做推送功能时,最烦得就是各种证书的问题,以前自己做的时候经常要反复搞那些证书搞好几遍才能成功,现在发现归根到底都是appid这个东西搞错了,做个笔记记下来,以免忘了. 首先是程序里面注册推送的变 ...
- IOS NSTimer和CADisplayLink的用法
IOS--NSTimer和CADisplayLink的用法 NSTimer初始化器接受调用方法逻辑之间的间隔作为它的其中一个参数,预设一秒执行30次.CADisplayLink默认每秒运行60次,通过 ...
- iOS NSTimer
示例: //创建 scrollTimer =[NSTimer scheduledTimerWithTimeInterval:interval target:self selector:@selecto ...
- ios NSTimer的强引用问题
在一个controller中,使用 NSURLSessionDataTask *dataTask = [[NSURLSession sharedSession] dataTaskWithRequest ...
- 【iOS】文件下载小记
下载文件到NSURLConnection与NSURLSession两种,一种有恨悠久的历史了. 使用相对麻烦,后者是新出来的,添加了一些额外的功能. 一.NSURLConnection实现下载 TIP ...
随机推荐
- POJ 3414 Pots (dfs,这个代码好长啊QAQ)
Description You are given two pots, having the volume of A and B liters respectively. The following ...
- Cisco基础(四):配置标准ACL、配置扩展ACL、配置标准命名ACL、配置扩展命名ACL
一.配置标准ACL 目标: 络调通后,保证网络是通畅的.同时也很可能出现未经授权的非法访问.企业网络既要解决连连通的问题,还要解决网络安全的问题. 配置标准ACL实现拒绝PC1(IP地址为192.16 ...
- redis集群-4
redis集群原理 redis cluster在设计的时候,就考虑到了去中心化,去中间件,也就是说,集群中的每个节点都是平等的关系,都是对等的,每个节点都保存各自的数据和整个集群的状态.每个节点都和其 ...
- 有关于css的四种布局
四种布局 (1).左右两侧,左侧固定宽度200px, 右侧自适应占满. (2).左中右三列,左右个200px固定,中间自适应占满. (3).上中下三行,头部200px高,底部200px高,中间自适应占 ...
- Android获取手机和系统版本等信息的代码
有时候需要统计手机的型号和版本号,利用程序可以获取到相应的手机信息,对比两部手机发现,厂商不同,某个信息显示方式也不尽相同,具体见: String phoneInfo = "Product: ...
- springboot controller传参,对象映射
Post请求,对象映射时,在参数 加 @RequestBody: 传入对象内字段的json才能映射 {"legendData": [100,90,80,70,60,50,40,30 ...
- (55)C# windows 消息
窗体捕获消息 namespace WindowsFormsApp1 { public partial class Form1 : Form { public Form1() { InitializeC ...
- freemark 语法
我们通过后端model. addAttribute() 传递到前端的值来进行界面渲染 它的循环语句 和其他的有点不同: if 循环 <#if 条件语句> </#if> if ...
- 【狼】狼的unity3d脚本学习
记录学习中的问题,时刻更新 unity获取鼠标所在位置 BOOL GetCursorPos( LPPOINT lpPoint); 获取鼠标所在位置,不过原点在左下角 ///////////// ...
- Haproxy+ssl+nvm+forever
1 nvm介绍 NVM(Node version manager)顾名思义,就是Node.js的版本管理软件,可以轻松的在Node.js各个版本间切换,项目源码在GitHub: #安装git客户端 [ ...