2017-5-17 周四 晴
作者:58婚恋技术部
一,RunLoop
部分
启动
run loop
只对程序的辅助线程有意义。一个
run loop
通常必须包含一个输
入源或定时器来监听事件,如果一个都没有
,run loop
启动后立即退出。每个线程都有一个或多个
run loop,
主线程的
runloop
默认是打开的,而子线程的
runloop
则默认是关闭的,需要人为去打开,也就是执行
run()
方法。
cocoa
中的
runloop
是非线程安全的,不能跨线程操作其他线程的
runloop
,而
core fundation
中的
runloop
是线程安全的,可以通过调用
getCFRunloop
方法得到对应的
core fundtion
的
runloop
已达到线程安全的目的。
由于
runloop
并非全自动的,所以我们需要通过
while/for
语句来驱动
runloop
能够循环运行,比如如下代码:
////////////BOOL isRunning = NO;
////////////do {
////////////isRunning =
[[NSRunLoop currentRunLoop]
runMode:NSDefaultRunLoopMode beforeDate:
[NSDate distantFuture]
];
////////////} while (isRunning);
但是上面代码有几个疑问,
问题一,就是用什么来触发
runloop
结束?
答案是这样的,
runMode
方法是在当前
runloop
中在给定的时间内等待一个输入源,而输入源有两种,一个是
port
的方式,一个是
performSelector
的方式,所以上面这个等待输入源的
runloop
在接到其他线程
perform
过来的
selector
就可以运行结束了。
问题二,为什么这个
runloop
只接受一个词
perform
就结束呢?而不是可以一直在这接受
perform
?
这个方法的作用就是只运行一次,直到一个指定时间或者有输入源时结束,所以
runloop
一般需要配合
while
等循环体使用,才能循环监听输入源
问题三,如何在一个子线程里面创建一个
runloop
并且运行他?
每个线程都会自动创建
runloop
,只是没有启动而已,我们
[NSRunLoop getCurrentRunLoop]
就可以得到当前线程的
runloop
,执行
run
方法就可以启动
runloop
。
问题四,一个
runloop
为什么会阻塞线程?
runloop
的概念本来就是一个黑洞,当线程运行到这个
runloop
中时就会把对应
mode
的资源交给
runloop
,这个时候
runloop
就会去处理对应的输入源或者定时源事件,程序进入
runloop
就会进入
runloop
的生命周期,该线程下
runloop
外面的代码不会执行,除非
runloop
结束,就会继续往下执行。所以这个
mode
就把事件进行了分类,有
default
,
connect
,
tracking
等等,
二,perform
Selector的实际意义
下面方法定义在
nsobject
中,是可以在其他线程中执行的
seelctor
,并非是创建新线程,而是线程之间通讯,这个方法会触发另外一个线程的输入源,
runloop
若运行就会检测的到
=================================
performSelectorOnMainThread:withObject:waitUntilDone:
performSelectorOnMainThread:withObject:waitUntilDone:modes: //modes
是指
runloop
的模型
performSelector:onThread:withObject:waitUntilDone:
performSelector:onThread:withObject:waitUntilDone:modes:
performSelector:withObject:afterDelay:
performSelector:withObject:afterDelay:inModes:
cancelPreviousPerformRequestsWithTarget://
取消掉《
performSelector:withObject:afterDelay:
》
cancelPreviousPerformRequestsWithTarget:selector:object:
疑问,
1,cocoa的runloop是非线程安全的,那么
perform这种通讯机制明显在cocoa中完成,为什么又没有问题呢?
答案:
一,是因为performSelector一个消息到其他线程时,其他线程的runloop并没有启动,
二,runloop若启动了,就要把对应的mode传过去,mode的获取方法是通过getCFRunloopMode方法得到。
三,runloop
的生命周期
==================================
Run loop
入口
kCFRunLoopEntry
Run loop
何时处理一个定时器
kCFRunLoopBeforeTimers
Run loop
何时处理一个输入源
Run loop
何时进入睡眠状态
Run loop
何时被唤醒
,
但在唤醒之前要处理的事件
Run loop
终止
四,NSRunLoop
基本方法
=============================
每个线程都会有一个
runloop
,这个
runloop
在干什么用呢,
NSRunLoop *timerRunLoop =
[NSRunLoop mainRunLoop]
;//
得到
mainrunloop
[timerRunLoop addTimer:timer forMode:]
//
把
timer
添加到
timerRunloop
中,
NSString* runLoopMode =
[[NSRunLoop currentRunLoop]
currentMode];//
得到当前线程
runloop
[[NSRunLoop currentRunLoop]
runMode:NSDefaultRunLoopMode beforeDate:
[NSDate distantFuture]
];//
这个方法会等待一个输入源,
////////////
比较实用的例子如下:
////////////NSThread *runLoopThread =
[[NSThread alloc]
initWithTarget:self selector:@selector(handleRunLoopThreadTask) object:nil];
////////////
[runLoopThread start]
;
////////////
使用
Run Loop
,在线程执行期间,
handleNormalButtonTouchUpInside
能够正常输入信息
////////////while (!self.normalThreadDidFinishFlag) {
////////////NSLog(@"Begin RunLoop");
////////////
[[NSRunLoop currentRunLoop]
runMode:NSDefaultRunLoopMode beforeDate:
[NSDate distantFuture]
];
////////////NSLog(@"End RunLoop");
////////////}
////////////
////////////
在线程的这个方法
handleRunLoopThreadTask
执行完了之后实用
performSelectorOnmainThread
来设置
self.normalThreadDidFinishFlag
的值结束
runMode
////////////
五,runloop
需要注意的事项
runloop
添加到
mainThread
的
mainRunLoop
中,就会出现卡死情况,因为阻塞了主线程,正常的做法是在
operation
中做,或者
NSThread
中做
runloop
的添加动作,在执行方法中再
perform
到其他
thread
中执行对应的
method
。
为了创建一
个
run loop
观察者
,
你可以创建一个
CFRunLoopObserverRef
类型的实例
run Loop
在处理输入事件时会产生通知,可以通过
Core Foundation
向线程中添加
run-loop observers
来监听特定事件,(这个怎么实现?)
六,runloop
的使用场景
=
====================================
Run loop
在你要和线程有更多的交互时才需要
,
比如以下情况
:
使用端口或自定义输入源来和其他线程通信
使用线程的定时器
Cocoa
中使用任何
performSelector...
的方法
使线程周期性工作
铁友火车票
ios
版
native
跟
lua
交互部分就是用的
runloop
控制整个流程
Run loop
对象提供了添加输入源
,
定时器和
run loop
的观察者以及启动
run loop
的接口
每个线程都有唯一的与之关联的
run loop
对象。在
Cocoa
中
,
该对象是
NSRunLoop
类的一个实例
七,
获得
runloop
===================(
没走通)
===============
//
把当前监听
netserviece
的输入源加入到
runloop
,然后移除
NSNetService *service =
[[NSNetService alloc]
initWithDomain:@"local" type:@"_crypttest._tcp" name:
[[UIDevice currentDevice]
name] port:55663];
[service publish]
;//
通知接收者
CFReadStreamRef readStream = NULL;
CFReadStreamSetProperty(readStream, kCFStreamPropertyShouldCloseNativeSocket, kCFBooleanTrue);
[readStream scheduleInRunLoop:[NSRunLoop currentRunLoop]
forMode:NSRunLoopCommonModes];
[readStream removeFromRunLoop:[NSRunLoop currentRunLoop]
forMode:NSRunLoopCommonModes];
//runloop
中添加
timer
NSDate *fireDate =
[NSDate dateWithTimeIntervalSinceNow:5.0]
;
NSTimer *cameraTimer =
[[NSTimer alloc]
initWithFireDate:fireDate interval:1.0 target:self selector:@selector(timedPhotoFire) userInfo:nil repeats:YES];
[[NSRunLoop mainRunLoop]
addTimer:cameraTimer forMode:NSDefaultRunLoopMode];
self.cameraTimer = cameraTimer;
//
注意
timer
要释放
if (
[self.cameraTimer isValid]
)
{
[self.cameraTimer invalidate]
;
}
//
八,runloopMode
的种类
==================================
1) NSDefaultRunLoopMode:
大多数工作中默认的运行方式。
2) NSConnectionReplyMode:
使用这个
Mode
去监听
NSConnection
对象的状态,我们很少需要自己使用这个
Mode
。
3) NSModalPanelRunLoopMode:
使用这个
Mode
在
Model Panel
情况下去区分事件
(OS X
开发中会遇到
)
。
4) UITrackingRunLoopMode:
使用这个
Mode
去跟踪来自用户交互的事件(比如
UITableView
上下滑动)。
5) GSEventReceiveRunLoopMode:
用来接受系统事件,内部的
Run Loop Mode
。
6) NSRunLoopCommonModes:
这是一个伪模式,其为一组
run loop mode
的集合。如果将
Input source
加入此模式,意味着关联
Input source
到
Common Modes
中包含的所有模式下。在
iOS
系统中
NSRunLoopCommonMode
包含
NSDefaultRunLoopMode
、
NSTaskDeathCheckMode
、
UITrackingRunLoopMode.
可使用
CFRunLoopAddCommonMode
方法向
Common Modes
中添加自定义
mode
。
九,两个实际问题(没有实际验证过)
1,如何在后台线程运行NSURLConnection====== http://wufawei.com/2013/05/use-NSRunLoop/
2,解决NSURLConnection在用户滚动UIScrollView或者UITableView不执行的问题
。===== http://wufawei.com/2013/05/use-NSRunLoop/
========================runloop
拓展阅读
==================================
http://blog.csdn.net/wzzvictory/article/details/9237973
http://chun.tips/blog/2014/10/20/zou-jin-run-loopde-shi-jie-%5B%3F%5D-:shi-yao-shi-run-loop%3F/
http://chun.tips/blog/2014/10/20/zou-jin-run-loopde-shi-jie-er-:ru-he-pei-zhi-run-loop-sources/