runloop 简介

+++
Categories = ["iOS",]
Tags = ["iOS","runloop",]
date = "2014-06-26T19:49:43+08:00"
title = "runloop 简介"

+++

runloop 和线程有什么关系?

总的来说,Runloop,如其名,表示着一直在运行的循环。实际上,runloop和线程是紧密相连的,可以这样说runloop是为了线程而生,没有线程,它就没有存在的必要。每个线程,包括程序的主线程(main thread)都有与之对应的runloop对象。

  1. 主线程的runloop默认是启动的。

iOS的应用程序里面,程序启动后会有一个如下的 main() 函数

int main(int argc, char * argv[]) {
    @autoreleasepool {
        return UIApplicationMain(argc, argv, nil, NSStringFromClass([AppDelegate class]));
    }
}

重点是UIApplicationMain()函数,这个方法会为main thread设置一个NSRunLoop对象,这就解释了,为什么我们的应用可以在无人操作的时候休息,需要让它干活的时候又能立马响应。

  1. 对其他线程来说,runloop默认是没有启动的,如果你需要更多的线程交互则可以手动配置和启动,如果线程只是去执行一个长时间的已确定的任务则不需要。

  2. 在任何一个cocoa程序的线程中,都可以通过以下代码来获取到当前的runloop。

    NSRunLoop *runloop = [NSRunLoop currentRunLoop];

runloop的mode主要来指定事件在运行中的优先级

  • NSDefaultRunLoopMode(kCFRunLoopDefaultMode):默认,空闲状态
  • UITrackingRunLoopMode:ScrollView滑动时
  • UIInitializationRunLoopMode:启动时
  • NSRunLoopCommonModes(kCFRunLoopCommonModes)

苹果公开提供的 Mode 有两个:

  1. NSDefaultRunLoopMode(kCFRunLoopDefaultMode)
  2. NSRunLoopCommonModes(kCFRunLoopCommonModes)

runloop 只能运行在一中mode 中

RunLoop只能运行在一种mode下,如果要换mode,当前的loop也需要停下重启成新的。利用这个机制,ScrollView滚动过程中NSDefaultRunLoopMode(kCFRunLoopDefaultMode)的mode会切换到UITrackingRunLoopMode来保证ScrollView的流畅滑动:只能在NSDefaultRunLoopMode模式下处理的事件会影响scrllView的滑动。

如果我们把一个NSTimer对象以NSDefaultRunLoopMode(kCFRunLoopDefaultMode)添加到主运行循环中的时候, ScrollView滚动过程中会因为mode的切换,而导致NSTimer将不再被调度。

同时因为mode还是可定制的,所以:

Timer计时会被scrollView的滑动影响的问题可以通过将timer添加到NSRunLoopCommonModes(kCFRunLoopCommonModes)来解决。代码如下:

//将timer添加到NSDefaultRunLoopMode中
[NSTimer scheduledTimerWithTimeInterval:1.0
                                 target:self
                               selector:@selector(timerTick:)
                               userInfo:nil
                                repeats:YES];
//然后再添加到NSRunLoopCommonModes里
NSTimer *timer = [NSTimer timerWithTimeInterval:1.0
                                         target:self
                                       selector:@selector(timerTick:)
                                       userInfo:nil
                                        repeats:YES];
[[NSRunLoop currentRunLoop] addTimer:timer forMode:NSRunLoopCommonModes];

runloop内部实现

一般来讲,一个线程一次只能执行一个任务,执行完成后线程就会退出。如果我们需要一个机制,让线程能随时处理事件但不退出,通常的代码逻辑:

function loop() {
    initialize();
    do {
        var message = get_next_message();
        process_message(message);
    } while (message != quit);
}

objc 管理对象内存

通过retainCount 的机制来决定对象是否需要释放。每次runloop的时候,都会检查对象的retainCount,如果retainCount为0,说明该对象没有地方需要继续使用了,可以释放掉了。

你可能感兴趣的:(runloop 简介)