Run loop就像它的名字一样,是你thread中的一个循环并对收到的事件进行处理。你可以把它理解成一个函数,线程启动run loop就是调用了类似这样的一个方法:
function loop() {
initialize();
do {
var message = get_next_message();
process_message(message);
} while (message != quit);
}
Run loop从两个不同的事件源中接收消息。Input sources(CFRunLoopSource)投递异步消息,通常来自于另一个thread或另一个应用程序。Timer sources(CFRunLoopTimer)当在计划的时间或重复的时间间隔内投递同步消息。两种事件源都使用应用程序指定的处理方式对到达的事件进行处理。下图展示了run loop和不同的事件源结构。
下来是Run Loop的使用场合:
1. 使用port或是自定义的input source来和其他线程进行通信
2. 在线程(非主线程)中使用timer
3. 使用 performSelector…系列(如performSelectorOnThread, …)
4. 使用线程执行周期性工作
NSTimer的工作原理:
一个 NSTimer 注册到 RunLoop 后,RunLoop 会为其重复的时间点注册好事件。例如 10:00, 10:10, 10:20 这几个时间点。RunLoop为了节省资源,并不会在非常准确的时间点回调这个Timer。Timer 有个属性叫做 Tolerance (宽容度),标示了当时间点到后,容许有多少最大误差。
如果某个时间点被错过了,例如执行了一个很长的任务,则那个时间点的回调也会跳过去,不会延后执行。就比如等公交,如果 10:10 时我忙着玩手机错过了那个点的公交,那我只能等 10:20 这一趟了。
NSTimer在子线程:
主线程的Run loop在应用程序的main函数中已经启动了,所以我们在主线程中使用定时器是可以正常运行的。
UIApplicationMain(argc, argv, nil, NSStringFromClass([AppDelegate class]))
在子线程中如果想要定时器能正常工作的话,那必须启动子线程的run loop:
- (void)threadBody
{
//此种方式创建的timer已经添加至runloop中
// [NSTimer scheduledTimerWithTimeInterval:1 target:self selector:@selector(doTask:) userInfo:nil repeats:YES];
// [[NSRunLoop currentRunLoop] run];
//此种方式创建的timer没有添加至runloop中
NSTimer *timer = [NSTimer timerWithTimeInterval:1 target:self selector:@selector(doTask:) userInfo:nil repeats:YES];
[[NSRunLoop currentRunLoop] addTimer:timer forMode:NSDefaultRunLoopMode];
[[NSRunLoop currentRunLoop] run];
}
- (void)doTask:(NSTimer *)t
{
NSLog(@"sss");
}
当然,这里只是很简单的介绍了一下run loop的原理,以为NSTimer在run loop中运行的原理,想深入学习RunLoop的可以去这里面看一下这里写链接内容