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属性设置宽容度。
网友评论