摘要:本文将带你了解IOS开发入门RunLoop 总结:RunLoop的应用场景(二),希望本文对大家学IOS有所帮助。
本文将带你了解IOS开发入门RunLoop 总结:RunLoop的应用场景(二),希望本文对大家学IOS有所帮助。
RunLoop 总结:RunLoop的应用场景(二)
参考资料
好的书籍都是值得反复看的,那好的文章,好的资料也值得我们反复看。我们在不同的阶段来相同的文章或资料或书籍都能有不同的收获,那它就是好文章,好书籍,好资料。
关于iOS 中的RunLoop资料非常的少,以下资料都是非常好的。
CF框架源码(这是一份很重要的源码,可以看到CF框架的每一次迭代,我们可以下载最新的版本来分析,或与以下文章对比学习。目前最新的是CF-1153.18.tar.gz)RunLoop官方文档(学习iOS的任何技术,官方文档都是入门或深入的极好手册;我们也可以在Xcode—>Help—>Docementation and API Reference —>搜索RunLoop—> Guides(59)—>《Threading Programming Guide:Run Loops》这篇即是)深入理解RunLoop(不要看到右边滚动条很长,其实文章占篇幅2/5左右,下面有很多的评论,可见这篇文章的火热)RunLoop个人小结 (这是一篇总结的很通俗容易理解的文章)sunnyxx线下分享RunLoop(这是一份关于线下分享与讨论RunLoop的视频,备用地址:https://pan.baidu.com/s/1pLm4Vf9)iPhonedevwiki中的CFRunLoop(commonModes中其实包含了三种Mode,我们通常知道两种,还有一种是啥,你知道么?)维基百科中的Event loop(可以看看这篇文章了解一下事件循环)
使用场景
1.我们经常会在应用中看到tableView 的header 上是一个横向ScrollView,一般我们使用NSTimer,每隔几秒切换一张图片。可是当我们滑动tableView的时候,顶部的scollView并不会切换图片,这可怎么办呢?
2.界面上除了有tableView,还有显示倒计时的Label,当我们在滑动tableView时,倒计时就停止了,这又该怎么办呢?
场景中的代码实现
我们的定时器Timer是怎么写的呢?
一般的做法是,在主线程(可能是某控制器的viewDidLoad方法)中,创建Timer。
可能会有两种写法,但是都有上面的问题,下面先看下Timer的两种写法:
<code>// 第一种写法
NSTimer *timer = [NSTimer timerWithTimeInterval:1.0 target:self selector:@selector(timerUpdate) userInfo:nil repeats:YES];
[[NSRunLoop currentRunLoop] addTimer:timer forMode:NSDefaultRunLoopMode];
[timer fire];
// 第二种写法
[NSTimer scheduledTimerWithTimeInterval:1.0 target:self selector:@selector(timerUpdate) userInfo:nil repeats:YES];</code>
上面的两种写法其实是等价的。第二种写法,默认也是将timer添加到NSDefaultRunLoopMode下的,并且会自动fire。。
要验证这一结论,我们只需要在timerUpdate方法中,将当前runLoop的currentMode打印出来即可。
<code><code>- (void)timerUpdate
{
NSLog(@"当前线程:%@",[NSThread currentThread]);
NSLog(@"启动RunLoop后--%@",[NSRunLoop currentRunLoop].currentMode);
// NSLog(@"currentRunLoop:%@",[NSRunLoop currentRunLoop]);
dispatch_async(dispatch_get_main_queue(), ^{
self.count ++;
NSString *timerText = [NSString stringWithFormat:@"计时器:%ld",self.count];
self.timerLabel.text = timerText;
});
}
// 控制台输出结果:
2016-12-02 15:33:57.829 RunLoopDemo02[6698:541533] 当前线程:<nsthread: 0x600000065500="">{number = 1, name = main}
2016-12-02 15:33:57.829 RunLoopDemo02[6698:541533] 启动RunLoop后--kCFRunLoopDefaultMode</nsthread:></code></code>
然后,我们在滑动tableView的时候timerUpdate方法,并不会调用。
* 原因是啥呢?*
原因是当我们滑动scrollView时,主线程的RunLoop 会切换到UITrackingRunLoopMode这个Mode,执行的也是UITrackingRunLoopMode下的任务(Mode中的item),而timer 是添加在NSDefaultRunLoopMode下的,所以timer任务并不会执行,只有当UITrackingRunLoopMode的任务执行完毕,runloop切换到NSDefaultRunLoopMode后,才会继续执行timer。
* 要如何解决这一问题呢?*
解决方法很简单,我们只需要在添加timer 时,将mode 设置为NSRunLoopCommonModes即可。
<code><code><code><code><code><code>- (void)timerTest
{
// 第一种写法
NSTimer *timer = [NSTimer timerWithTimeInterval:1.0 target:self selector:@selector(timerUpdate) userInfo:nil repeats:YES];
[[NSRunLoop currentRunLoop] addTimer:timer forMode:NSRunLoopCommonModes];
[timer fire];
// 第二种写法,因为是固定添加到defaultMode中,就不要用了
}</code></code></code></code></code></code>
从RunLoop官方文档和 iPhonedevwiki中的CFRunLoop可以看出,NSRunLoopCommonModes并不是一种Mode,而是一种特殊的标记,关联的有一个set ,官方文档说:For Cocoa applications, this set includes the default, modal, and event tracking modes by default.(默认包含NSDefaultRunLoopMode、NSModalPanelRunLoopMode、NSEventTrackingRunLoopMode)
添加到NSRunLoopCommonModes中的还没有执行的任务,会在mode切换时,再次添加到当前的mode中,这样就能保证不管当前runloop切换到哪一个mode,任务都能正常执行。并且被添加到NSRunLoopCommonModes中的任务会存储在runloop 的commonModeItems中。
其他一些关于timer的坑
我们在子线程中使用timer,也可以解决上面的问题,但是需要注意的是把timer加入到当前runloop后,必须让runloop 运行起来,否则timer仅执行一次。
示例代码:
<code><code><code><code><code><code><code><code><code>//首先是创建一个子线程
- (void)createThread
{
NSThread *subThread = [[NSThread alloc] initWithTarget:self selector:@selector(timerTest) object:nil];
[subThread start];
self.subThread = subThread;
}
// 创建timer,并添加到runloop的mode中
- (void)timerTest
{
@autoreleasepool {
NSRunLoop *runLoop = [NSRunLoop currentRunLoop];
NSLog(@"启动RunLoop前--%@",runLoop.currentMode);
NSLog(@"currentRunLoop:%@",[NSRunLoop currentRunLoop]);
// 第一种写法,改正前
// NSTimer *timer = [NSTimer timerWithTimeInterval:1.0 target:self selector:@selector(timerUpdate) userInfo:nil repeats:YES];
// [[NSRunLoop currentRunLoop] addTimer:timer forMode:NSDefaultRunLoopMode];
// [timer fire];
// 第二种写法
[NSTimer scheduledTimerWithTimeInterval:1.0 target:self selector:@selector(timerUpdate) userInfo:nil repeats:YES];
[[NSRunLoop currentRunLoop] run];
}
}
//更新label
- (void)timerUpdate
{
NSLog(@"当前线程:%@",[NSThread currentThread]);
NSLog(@"启动RunLoop后--%@",[NSRunLoop currentRunLoop].currentMode);
NSLog(@"currentRunLoop:%@",[NSRunLoop currentRunLoop]);
dispatch_async(dispatch_get_main_queue(), ^{
self.count ++;
NSString *timerText = [NSString stringWithFormat:@"计时器:%ld",self.count];
self.timerLabel.text = timerText;
});
}
</code></code></code></code></code></code></code></code></code>
添加timer 前的控制台输出:
添加timer后的控制台输出:
从控制台输出可以看出,timer确实被添加到NSDefaultRunLoopMode中了。可是添加到子线程中的NSDefaultRunLoZ喎?"/kf/ware/vc/" target="_blank">vcE1vZGXA76Oszt7C28jnus659ravo6x0aW1lcra8xNy5u7rc1f2zo7XE1MvXqqGj1eLT1srHzqrJtsTYo788L2NvZGU+PC9jb2RlPjwvY29kZT48L2NvZGU+PC9jb2RlPjwvY29kZT48L2NvZGU+PC9jb2RlPjwvY29kZT48L2NvZGU+PC9jb2RlPjwvcD4NCjxwPjxjb2RlPjxjb2RlPjxjb2RlPjxjb2RlPjxjb2RlPjxjb2RlPjxjb2RlPjxjb2RlPjxjb2RlPjxjb2RlPjxjb2RlPtXivs3Kx7bgz9+zzNPrcnVubG9vcLXEudjPtcHLo6zDv9K7uPbP37PMtrzT0NK7uPbT69auudjBqrXEUnVuTG9vcKOstvjDv9K7uPZSdW5Mb29wv8nE3Lvh09C24Lj2TW9kZaGjQ1BVu+HU2rbguPbP37PMvOTH0Lu7wLTWtNDQyM7O8aOss8rP1rP2tuC49s/fs8zNrMqx1rTQ0LXE0Ke5+6Gj1rTQ0LXEyM7O8cbkyrW+zcrHUnVuTG9vcMiluPe49k1vZGXA79a00NC497j2aXRlbaGj0vLOqlJ1bkxvb3DKx7bAwaK1xMG9uPajrM/gu6Wyu7vh07DP7KOsy/nS1NTa19PP37PMzO2803RpbWVyo6y7rLavytPNvMqxo6x0aW1lcsTc1f2zo9TL0NChozwvY29kZT48L2NvZGU+PC9jb2RlPjwvY29kZT48L2NvZGU+PC9jb2RlPjwvY29kZT48L2NvZGU+PC9jb2RlPjwvY29kZT48L2NvZGU+PC9wPg0KPGgyIGlkPQ=="总结">总结
1、如果是在主线程中运行timer,想要timer在某界面有视图滚动时,依然能正常运转,那么将timer添加到RunLoop中时,就需要设置mode 为NSRunLoopCommonModes。
2、如果是在子线程中运行timer,那么将timer添加到RunLoop中后,Mode设置为NSDefaultRunLoopMode或NSRunLoopCommonModes均可,但是需要保证RunLoop在运行,且其中有任务。
本文由职坐标整理并发布,希望对同学们有所帮助。了解更多详情请关注职坐标移动开发之IOS频道!
您输入的评论内容中包含违禁敏感词
我知道了
请输入正确的手机号码
请输入正确的验证码
您今天的短信下发次数太多了,明天再试试吧!
我们会在第一时间安排职业规划师联系您!
您也可以联系我们的职业规划师咨询:
版权所有 职坐标-一站式IT培训就业服务领导者 沪ICP备13042190号-4
上海海同信息科技有限公司 Copyright ©2015 www.zhizuobiao.com,All Rights Reserved.
沪公网安备 31011502005948号