今天抽空复习了会Runloop,以前虽然特意的学过,但是工作中确比较少用到,所以利用今天这个机会把他记录下来。

Runloop意思就是运行循环,只有有了它,APP才能一直保持运行状态。Runloop的寄生于线程:一个线程只能有唯一对应的runloop;
Runloop内部就是一个死循环。但是他和一般的while(1);这种死循环还是有差别的。
Runloop的寄生于线程:一个线程只能有唯一对应的Runloop;
这就要讲到Runloop的几种模式。

目前接触到的几种Mode有:

/**
     *  Runloop的几种模式
     *
     *  1. NSDefaultRunLoopMode
     *  默认模式中几乎包含了所有输入源(NSConnection除外),一般情况下应使用此模式。
     *
     *  2. NSRunLoopCommonModes
     *  这是一个伪模式,其为一组run loop mode的集合,将输入源加入此模式意味着在Common Modes中包含的所有模式下都可以处理。
     *  包含NSDefaultRunLoopMode和UITrackingRunLoopMode
     *
     *  3. UITrackingRunLoopMode
     *  在拖动loop或其他user interface tracking loops时处于此种模式下,在此模式下会限制输入事件的处理。
     */
FOUNDATION_EXPORT NSString * const NSDefaultRunLoopMode;
FOUNDATION_EXPORT NSString * const NSRunLoopCommonModes NS_AVAILABLE(10_5, 2_0);

UIKIT_EXTERN NSString *const UITrackingRunLoopMode;

每个Mode中又包含若干个 Source/Observer/Timer

Source表示事件源,处理点击事件和一些系统事件。比如点击了一个按钮,系统会在添加一个点击事件到当前线程的Runloop里面的source中,然后在Runloop的下次循环中就会执行。

Observer是用来监听Runloop的状态的,Runloop对应几种状态

/* Run Loop Observer Activities */
typedef CF_OPTIONS(CFOptionFlags, CFRunLoopActivity) {
kCFRunLoopEntry = (1UL << 0),
kCFRunLoopBeforeTimers = (1UL << 1),
kCFRunLoopBeforeSources = (1UL << 2),
kCFRunLoopBeforeWaiting = (1UL << 5),
kCFRunLoopAfterWaiting = (1UL << 6),
kCFRunLoopExit = (1UL << 7),
kCFRunLoopAllActivities = 0x0FFFFFFFU
};

每当状态发生改变就会通知observer

Timer表示定时器,所以我们创建的NSTimer要添加到Runloop中才能有效。

注意:如果Runloop中 Source/Observer/Timer 这三者都为空,Runloop会自动退出。

Runloop使用:
前面讲到Runloop是寄生于线程的,主线程因为Runloop才保证能一直运行下去,那么我们可以试着创建一个子线程,子线程默认执行完就退出了,那么我们可以给他添加Runloop,让他保持不死,等待着我们给他添加一些新的任务。事实上SDWebImage框架就是这么做的。创建一个专门用于图片下载的线程。当有图片需要下载的时候就添加任务到这个线程中。我们也可以创建一条专门服务于自己的线程,如一直在子线程监听用户操作,遍历Document文件夹等等。