NSTimer直接使用需要在主线程中使用
2016-07-17 21:51
267 查看
NSTimer 的 scheduledTimerWithTimeInterval 方法使用时需要在主线程中使用否则不会执行的。
Loop中,且模式是默认的
Loop切换成
Loop中的Timer就不会执行。
所以为了设置一个不被UI干扰的Timer,我们需要手动创建一个Timer,然后使用
Loop中。这里使用的模式是:
参考代码:
输出:
Loop中循环执行的,因此Timer的回调方法不是在另一个线程的。那么怎样在真正的多线程环境下运行一个Timer呢?
可以先试试
Loop中,只不过这个是在另一个线程中,因此我们需要手动执行Run Loop(通过
完整代码如下:
输出:
因此先需要声明一个
接着通过
Source,接着通过
开始时间的类型是
然后通过
Source的事件回调,这里当然是使用Block了。
最后所有
完整代码:
输出:
原文链接:https://www.mgenware.com/blog/?p=459
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}
原文链接:https://www.mgenware.com/blog/?p=459
相关文章推荐
- Mootools 1.2教程 定时器和哈希简介
- C#定时器和随机数
- C#中timer定时器用法实例
- JS中自定义定时器让它在某一时刻执行
- JS定时器使用,定时定点,固定时刻,循环执行详解
- 理解javascript定时器中的setTimeout与setInterval
- JavaScript定时器详解及实例
- 基于jQuery实现的扇形定时器附源码下载
- jQuery基础的工厂函数以及定时器的经典实例分析
- 跟我学习javascript的定时器
- Qt定时器和随机数详解
- asp.net中Timer无刷新定时器的实现方法
- 解析Java中的定时器及使用定时器制作弹弹球游戏的示例
- libevent库的使用--定时器的使用实例
- MySQL定时器EVENT学习笔记
- js函数定时器实现定时读取系统实时连接数
- linux使用select实现精确定时器详解
- Cocos2d-x Schedule定时器的使用实例
- SSH框架网上商城项目第15战之线程、定时器同步首页数据
- VC定时器的用法实例详解