返回目录

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. URAL 1057 Amount of Degrees (数位dp)

    Create a code to determine the amount of integers, lying in the set [X;Y] and being a sum of exactly ...

  2. python笔试做错的题目

    a = [1,2,3] b = a print(id(a),id(b),a == b) print(a,b) b = b + [1,2,3] print(a,b) print(id(a),id(b), ...

  3. MySQL date_sub 和 date_add 函数

    DATE_SUB: 定义和用法 DATE_SUB() 函数从日期减去指定的时间间隔. 语法 DATE_SUB(date,INTERVAL expr type) date 参数是合法的日期表达式.exp ...

  4. 8、数值分析与matlab

    1.今天要拷matlab代码了,而且是很恶心的算法,估计也没几个人能看得懂,就连我自己都看不懂. 我也不知道这样做的意义何在,可能只是证明我在这世上曾经学过那么那么难的东西吧 首先是一个matlab版 ...

  5. PHP面试 javascript和jQuery 基础

    JavaScript基础 JavaScript语法 变量的定义:变量必须以字母开头   可以使用$和 _ 符号开头  变量名称对大小写敏感 使用 var 关键词声明变量   可以一次声明多个变量    ...

  6. Ngrinder简单使用

    文章目录 安装 试玩 性能测试 安装 https://github.com/naver/ngrinder/releases 下载对应版本,是一个war包,3.4以上支持jdk1.8 将war包放到to ...

  7. 运维01 VMware与Centos系统安装

    VMware与Centos系统安装   今日任务 1.Linux发行版的选择 2.vmware创建一个虚拟机(centos) 3.安装配置centos7 4.xshell配置连接虚拟机(centos) ...

  8. upc组队赛5 Hunter’s Apprentice 【判断多边形边界曲线顺逆时针】

    Hunter's Apprentice 题目描述 When you were five years old, you watched in horror as a spiked devil murde ...

  9. lambda(),map(),filter()

    Lambda 函数 Lambda 函数是一种比较小的匿名函数.Python 函数通常使用 def a_function_name() 样式来定义,但对于 lambda 函数,我们根本没为它命名.这是因 ...

  10. leetcode.矩阵.566重塑矩阵-Java

    1. 具体题目 给出一个由二维数组表示的矩阵,以及两个正整数r和c,分别表示想要的重构的矩阵的行数和列数.重构后的矩阵需要将原始矩阵的所有元素以相同的行遍历顺序填充.如果具有给定参数的reshape操 ...