iOS RunLoop

Runloop运行的本质

是一个do while 循环,执行后就一直处于等待-处理的循环之中,直到循环结束,它在休眠时几乎不会占用系统资源,是由系统内核负责实现的。

Runloop Mode

Runloop总是运行在某种疼的CFRunLoopModeRef下,每种Runloop都可以包含若干个Mode, 每个Mode又包含Source/Timer/Observer。当切换Mode时必须退出当前Mode,然后重新进入Runloop保证不同Mode的Source/Timer/Observer互不影响。

struct __CFRunLoop {
        CFRuntimeBase _base;
        pthread_mutex_t _lock;          /* locked for accessing mode list */
        __CFPort _wakeUpPort;           // used for CFRunLoopWakeUp 
        Boolean _unused;
        volatile _per_run_data *_perRunData;              // reset for runs of the run loop
        pthread_t _pthread;
        uint32_t _winthread;
        CFMutableSetRef _commonModes;
        CFMutableSetRef _commonModeItems;
        CFRunLoopModeRef _currentMode;
        CFMutableSetRef _modes;
        struct _block_item *_blocks_head;
        struct _block_item *_blocks_tail;
        CFAbsoluteTime _runTime;
        CFAbsoluteTime _sleepTime;
        CFTypeRef _counterpart;
    };
    
    struct __CFRunLoopMode {
        CFRuntimeBase _base;
        pthread_mutex_t _lock;  /* must have the run loop locked before locking this */
        CFStringRef _name;
        Boolean _stopped;
        char _padding[3];
        CFMutableSetRef _sources0;
        CFMutableSetRef _sources1;
        CFMutableArrayRef _observers;
        CFMutableArrayRef _timers;
        CFMutableDictionaryRef _portToV1SourceMap;
        __CFPortSet _portSet;
        CFIndex _observerMask;
    #if USE_DISPATCH_SOURCE_FOR_TIMERS
        dispatch_source_t _timerSource;
        dispatch_queue_t _queue;
        Boolean _timerFired; // set to true by the source when a timer has fired
        Boolean _dispatchTimerArmed;
    #endif
    #if USE_MK_TIMER_TOO
        mach_port_t _timerPort;
        Boolean _mkTimerArmed;
    #endif
    #if DEPLOYMENT_TARGET_WINDOWS
        DWORD _msgQMask;
        void (*_msgPump)(void);
    #endif
        uint64_t _timerSoftDeadline; /* TSR */
        uint64_t _timerHardDeadline; /* TSR */
    };
Runloop和线程的关系

Runloop是基于pthread进行管理的,pthread是基于C的跨平台多线程操作底层API。
线程和Runloop是一一对应的,子线程默认并不会创建Runloop,同时在子线程结束的时候也会销毁对应的Runloop.如果子线程保活时,执行完事件后,Runloop并不会销毁。

Runloop默认run方法:
- (void)run; 
- (BOOL)runMode:(NSRunLoopMode)mode beforeDate:(NSDate *)limitDate;
- (void)runUntilDate:(NSDate *)limitDate;

-(void)run;
- run方法对应CFRunloopRef中的CFRunLoopRun并不会退出,除非调用CFRunLoopStop();如果想要永远不会退出Runloop才会使用此方法,否则可以使用runUntilDate.

- (BOOL)runMode:(NSRunLoopMode)mode beforeDate:(NSDate *)limitDate;
对应CFRunLoopRunInMode(mode,limiteDate,true)方法,只执行一次,执行完就退出,通常用于手动控制Runloop(列如在while循环中)。可以用来停止保活子线程的Runloop.

- (void)runUntilDate:(NSDate *)limitDate;
对应CFRunLoopRunInMode(kCFRunLoopDefaultMode,limiteDate,false),执行完并不会退出,继续下一次Runloop知道timeout。
NSTimer

NSTimer创建的两种方式:
timerWithXXX: 需要手动添加当前runloop中,不添加到Runloop中的NSTimer是无法正常工作的。
scheduedTimeWithXXX: 会自动以NSDefaultRunLoopMode添加到当前Runloop中。
无论重复执行的定时器还是一次性定时器只要调用invalidate方法会变得无效(一次性定时器执行完操作后自动调用invalidate方法)。

如果想要使用NSTimer尽可能的准确,可以设置tolerance属性设置宽容度。

你可能感兴趣的:(iOS RunLoop)