版本记录
版本号 | 时间 |
---|---|
V1.0 | 2017.08.23 |
前言
NSRunloop
是OC Foundation
框架中非常重要的一个类,很多时候我们会使用它,但是未必对其有深入的了解,接下来几篇我就会带着大家重新学习一下NSRunloop
这个类,从简单到复杂,从基本到深化,我会一步步的走完。希望对大家有所帮助。感兴趣的可以看我上一篇。
1. NSRunloop简单细说(一)—— 整体了解
2. NSRunloop简单细说(二)—— 获取运行循环及其模式
3. NSRunloop简单细说(三)—— 定时器和端口
一、- (void)configureAsServer;
该方法已经被废弃了,一般都是用在NSConnection中等创建服务。
[[NSRunLoop currentRunLoop] configureAsServer]
结论:已经废弃。
二、- (void)run;
该方法的作用就是:将接收器置于永久循环中,在此期间处理来自所有附加输入源的数据。其实就是开启Runloop。
这里还有几点需要注意:
- 主线程的Runloop是默认开启的,子线程需要调用Runloop开启这个线程。
- 如果没有输入源或定时器连接到运行循环,则此方法立即退出; 否则,它通过重复调用
runMode:beforeDate:
来在NSDefaultRunLoopMode
中运行接收器。 换句话说,这种方法有效地开始一个无限循环,用于处理来自运行循环的输入源和定时器的数据。 - 从运行循环手动删除所有已知的输入源和定时器不能保证运行循环将退出。 macOS可以根据需要安装和删除其他输入源,以处理针对接收者线程的请求。 因此,这些源可能会阻止运行循环退出。
- 如果你想要运行循环终止,你不应该使用这个方法。 相反,使用其他运行方法之一,还可以在循环中检查自己的其他任意条件。 一个简单的例子如下:
BOOL shouldKeepRunning = YES; // global
NSRunLoop *theRL = [NSRunLoop currentRunLoop];
while (shouldKeepRunning && [theRL runMode:NSDefaultRunLoopMode beforeDate:[NSDate distantFuture]]);
程序中的其他地方应该将KeepRunning设置为NO。
结论:这个可以看一下。
三、- (BOOL)runMode:(NSRunLoopMode)mode beforeDate:(NSDate *)limitDate;
该方法的作用就是:运行循环一次,阻塞在指定模式下的输入,直到给定的日期到达。这里的两个参数就不多说了,有了前面的基础,这两个参数还是很好理解的。我们这里就说一下返回值吧。
-
return
:如果运行循环运行并处理输入源或者达到指定的超时值,则为“YES” 否则,如果运行循环无法启动,则为NO。
还有几点需要注意:
- 如果没有输入源或定时器连接到运行循环,此方法立即退出并返回NO; 否则,在第一个输入源被处理或达到limitDate之后返回。 从运行循环中手动删除所有已知的输入源和定时器并不能保证运行循环将立即退出。 macOS可以根据需要安装和删除其他输入源,以处理针对接收者线程的请求。 因此,这些源可能会阻止运行循环退出。
- 定时器不被认为是输入源,并且可能在等待该方法返回时多次触发。
这里我们说一下使用情况,在单线程的app中,不需要注意Run Loop,但不代表没有。程序启动时,系统已经在主线程中加入了Run Loop。它保证了我们的主线程在运行起来后,就处于一种“等待”的状态(而不像一些命令行程序一样运行一次就结束了),这个时候如果有接收到的事件(Timer的定时到了或是其他线程的消息),就会执行任务,否则就处于休眠状态。如果我们要写多线程的程序,可能就需要自己来管理Run Loop。
下面看一下示例代码
- (void)getServer:(NSDictionary *)userInfo
{
NSURL *url = [NSURL URLWithString:[NSString stringWithFormat:@"http://%@:%@/Services/AccessGate/?tag/im", ip,port]];
NSMutableURLRequest *theRequest = [NSMutableURLRequest requestWithURL:url];
NSURLConnection *theConnection = [[[NSURLConnection alloc] initWithRequest:theRequest delegate:self] autorelease];
while (!finished) {
[[NSRunLoop currentRunLoop] runMode:NSDefaultRunLoopMode beforeDate:[NSDate distantFuture]];
}
[pool release];
}
上面的代码的作用就是:去请求一个文件,只到我们获取到文件为止,即finished == yes
。
结论:这个可以看一下。
四、- (void)runUntilDate:(NSDate *)limitDate;
该方法的作用就是:运行循环直到指定的日期,在此期间,它处理所有附加的输入源的数据。
还有几个问题需要注意:
- 如果没有输入源或定时器连接到运行循环,则此方法立即退出;否则,它通过重复调用
runMode:beforeDate:
在NSDefaultRunLoopMode
中运行接收器,直到指定的到期日期。 - 从运行循环手动删除所有已知的输入源和定时器不能保证运行循环将退出。 macOS可以根据需要安装和删除其他输入源,以处理针对接收者线程的请求。 因此,这些源可能会阻止运行循环退出。
- 同run方法,增加超时参数
limitDate
,避免进入无限循环。使用在UI线程(亦即主线程)上,可以达到暂停的效果。 - 使用run loop的一个好处就是避免线程轮询的开销,run loop在无事件处理时可以自动进入睡眠状态,降低CPU的能耗。
[[NSRunLoop mainRunLoop] run]; //主线程永远等待,但让出主线程时间片
[[NSRunLoop mainRunLoop] runUntilDate:[NSDate distantFuture]]; //等同上面调用
[[NSRunLoop mainRunLoop] runUntilDate:[NSDate date]]; //立即返回
[[NSRunLoop mainRunLoop] runUntilDate:[NSDate dateWithTimeIntervalSinceNow:10.0]]; //主线程等待,但让出主线程时间片,然后过10秒后返回
[[NSRunLoop mainRunLoop] runMode:NSDefaultRunLoopMode beforeDate: [NSDate distantFuture]]; //主线程等待,但让出主线程时间片;有事件到达就返回,比如点击UI等。
[[NSRunLoop mainRunLoop] runMode:NSDefaultRunLoopMode beforeDate: [NSDate date]]; //立即返回
[[NSRunLoop mainRunLoop] runMode:NSDefaultRunLoopMode beforeDate: [NSDate dateWithTimeIntervalSinceNow:10.0]]; //主线程等待,但让出主线程时间片;有事件到达就返回,如果没有则过10秒返回。
结论:这几个方法在多线程中还是很有用的,用好了可以解决很多问题。
五、- (void)acceptInputForMode:(NSRunLoopMode)mode beforeDate:(NSDate *)limitDate;
该方法的作用就是:运行循环一次或直到指定日期,仅接受指定模式的输入。
还有几点需要注意:
- 如果没有输入源或定时器连接到运行循环,则此方法立即退出;否则,它运行一次运行循环,只要一个输入源处理消息或指定的时间过去了就会返回。
- 定时器不被认为是输入源,并且可能在等待该方法返回时多次触发。
- 从运行循环手动删除所有已知的输入源和定时器不能保证运行循环将退出。 macOS可以根据需要安装和删除其他输入源,以处理针对接收者线程的请求。 因此,这些源可能会阻止运行循环退出。
结论:我表示这个方法我也没用过,不过想尝试用下。
参考文章
1. - (BOOL)runMode:(NSString *)mode beforeDate:(NSDate *)limitDate 方法 详解
2. 关于 NSTimer 和 NSRunLoop 的一些理解
后记
未完,待续~~~
网友评论