返回目录

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使用小记的更多相关文章

  1. iOS NSTimer使用详解 开启、关闭、移除

    定时器定时器详解ios定时器关闭定时器NSTimer 一,要使用一个定时器首先要定义一个定时器: @property (strong, nonatomic) NSTimer *myTimer;//定时 ...

  2. 【转】IOS NSTimer 定时器用法总结

    原文网址:http://my.oschina.net/u/2340880/blog/398598 NSTimer在IOS开发中会经常用到,尤其是小型游戏,然而对于初学者时常会注意不到其中的内存释放问题 ...

  3. IOS NSTimer 定时器用法总结

    NSTimer在IOS开发中会经常用到,尤其是小型游戏,然而对于初学者时常会注意不到其中的内存释放问题,将其基本用法总结如下: 一.初始化方法:有五种初始化方法,分别是 + (NSTimer *)ti ...

  4. ios - NSTimer中target的self是强引用问题

    当控制器ViewController跳转进入控制器OneViewController中的时候开启定时器,让定时器每隔一段时间打印一次,当OneViewController dismiss的时候,控制器 ...

  5. iOS 推送小记

    ios做推送功能时,最烦得就是各种证书的问题,以前自己做的时候经常要反复搞那些证书搞好几遍才能成功,现在发现归根到底都是appid这个东西搞错了,做个笔记记下来,以免忘了. 首先是程序里面注册推送的变 ...

  6. IOS NSTimer和CADisplayLink的用法

    IOS--NSTimer和CADisplayLink的用法 NSTimer初始化器接受调用方法逻辑之间的间隔作为它的其中一个参数,预设一秒执行30次.CADisplayLink默认每秒运行60次,通过 ...

  7. iOS NSTimer

    示例: //创建 scrollTimer =[NSTimer scheduledTimerWithTimeInterval:interval target:self selector:@selecto ...

  8. ios NSTimer的强引用问题

    在一个controller中,使用 NSURLSessionDataTask *dataTask = [[NSURLSession sharedSession] dataTaskWithRequest ...

  9. 【iOS】文件下载小记

    下载文件到NSURLConnection与NSURLSession两种,一种有恨悠久的历史了. 使用相对麻烦,后者是新出来的,添加了一些额外的功能. 一.NSURLConnection实现下载 TIP ...

随机推荐

  1. JRE和JVM的区别

    JRE和JVM的区别       JRE(JavaRuntimeEnvironment,Java运行环境),也就是Java平台.所有的Java程序都要在JRE下才能运行.JDK的工具也是Java程序, ...

  2. eclipse 中的.classpath和.project文件的具体作用(转)

    转载博客:http://www.cnblogs.com/panjun-Donet/archive/2010/08/25/1807780.html .project是项目文件,项目的结构都在其中定义,比 ...

  3. ListView 分页显示(转载+修改)上

    实习工作中,分配到了一个给已经上线的android成品增加需求的任务,其中一项是给每个信息显示增加分页显示的功能(ListView的显示),于是上网查资料,看到了: 原地址:http://www.cn ...

  4. 求最小生成树(暴力法,prim,prim的堆优化,kruskal)

    求最小生成树(暴力法,prim,prim的堆优化,kruskal) 5 71 2 22 5 21 3 41 4 73 4 12 3 13 5 6 我们采用的是dfs的回溯暴力,所以对于如下图,只能搜索 ...

  5. Nginx网络架构实战学习笔记(一):Nginx简介、安装、信号控制、nginx虚拟主机配置、日志管理、location 语法、Rewrite语法详解

    文章目录 nginx简介 nginx安装 nginx信号控制 nginx虚拟主机配置 日志管理 location 语法 精准匹配的一般匹配 正则匹配 总结 Rewrite语法详解 nginx简介 Ng ...

  6. 中国HBase技术社区第一届Meetup资料大合集

    2018年6月6号,由中国HBase技术社区组织,阿里云主办的中国第一次HBase Meetup在北京望京阿里中心举行,来自阿里.小米.滴滴.360等公司的各位HBase的PMC.committer共 ...

  7. Tomcat启动脚本(2)catalina.bat

    @echo off rem Licensed to the Apache Software Foundation (ASF) under one or more rem contributor lic ...

  8. 大型项目必备IPC之Binder机制原理(一)

    阿里P7Android高级架构进阶视频免费学习请点击:https://space.bilibili.com/474380680 摘要 Binder是Android系统进程间通信(IPC)方式之一.Li ...

  9. Centos 文件权限修改

    1.查看权限 # ls -l dirPath 2.修改权限,root权限执行(-R 子目录的权限都会改变) # chmod -R dirPath

  10. go中的string操作

    strings 判断字符串s是否以prefix开头 strings.HasPrefix(s string,preffix string) bool: 判断字符串s是否以suffix结尾 stirngs ...