runloop

runloop的目的是在有工作要做时让线程忙碌,在没有工作时让线程休眠。
runloop管理不是完全自动的,只有子线程需要run。主线程上自动设置并运行runloop。runloop应该是个对象。可以自定义mode,但是内容是系统的。
runloop从两种不同类型的源接收事件。Input source和Timer source。input source传递异步事件,并导致runUntilDate:退出。计时器源将事件交付给它们的处理程序例程,但不会导致运行循环退出。
Port-Based Sources由内核自动发出信号。Custom Input Sources必须从另一个线程手动发出信号。
在创建输入源时,将其分配给运行循环的一个或多个模式。模式影响在任何给定时刻监视哪些输入源。大多数情况下,运行运行循环是在默认模式下进行的,但是也可以指定自定义模式。如果输入源不处于当前监视模式,则它生成的任何事件都将保持到运行循环以正确模式运行为止。
iOS中没有NSPortMessage,只有MacOS里可以。
NSPort有三个子类.NSMachPort,NSMessagePort,NSSocketPort。
在其他线程中performing a selector,目标线程必须有一个活动Run loop。runloop每次在循环中处理所有排队的执行选择器调用,而不是在每次循环迭代中处理一个。
以下情况需要用Runloop
使用端口或自定义输入源与其他线程通信。
在线程上使用计时器。
在Cocoa应用程序中使用任何performSelector…方法。
保持线程在周围执行周期性任务。


9361533103369_.pic_hd.jpg

9411533104093_.pic_hd.jpg

9431533104116_.pic_hd.jpg

RunLoop 实际上就是一个对象,这个对象管理了其需要处理的事件和消息,线程和 RunLoop 之间是一一对应的,其关系是保存在一个全局的 Dictionary 里。线程刚创建时并没有 RunLoop,如果你不主动获取,那它一直都不会有。RunLoop 的创建是发生在第一次获取时,RunLoop 的销毁是发生在线程结束时。你只能在一个线程的内部获取其 RunLoop(主线程除外)。
对于RunLoop是在子线程创建时创建的还是在第一获取时创建的我无法知道。只能觉得从逻辑上。如果系统自己会创建一下的话。肯定不会在get方法里写着if (!) init();
CFRunLoopRef 是在 CoreFoundation 框架内的,它提供了纯 C 函数的 API,所有这些 API 都是线程安全的。
NSRunLoop 是基于 CFRunLoopRef 的封装,提供了面向对象的 API,但是这些 API 不是线程安全的。
属性一: currentRunLoop
属性二:currentMode
属性三: mainRunLoop

方法一: limitDateForMode
Discussion:得到runloop的limitDate
OC

- (NSDate *)limitDateForMode:(NSRunLoopMode)mode;
[myRunLoop runUntilDate:[NSDate dateWithTimeIntervalSinceNow:3]];
NSLog(@"limit%@", [[NSRunLoop currentRunLoop] limitDateForMode:NSDefaultRunLoopMode]);

方法二:getCFRunLoop
OC

- (CFRunLoopRef)getCFRunLoop;
[myRunLoop getCFRunLoop];

方法三:addTimer:forMode:
Discussion:
OC

- (void)addTimer:(NSTimer *)timer forMode:(NSRunLoopMode)mode;

方法四:getCFRunLoop
OC

- (CFRunLoopRef)getCFRunLoop;
[[NSRunLoop currentRunLoop] getCFRunLoop];

方法五:addTimer:forMode:
OC

- (void)addTimer:(NSTimer *)timer forMode:(NSRunLoopMode)mode;
NSTimer *timer = [NSTimer timerWithTimeInterval:10 target:self selector:@selector(doFireTimer:) userInfo:nil repeats:YES];
[myRunLoop addTimer:timer forMode:NSRunLoopCommonModes];

方法六:addPort:forMode:
OC

- (void)addPort:(NSPort *)aPort forMode:(NSRunLoopMode)mode;
NSPort *myPort = [NSMachPort port];
[myPort setDelegate:self];
[[NSRunLoop currentRunLoop] addPort:myPort forMode:NSDefaultRunLoopMode];

方法七:removePort:forMode:
OC

- (void)removePort:(NSPort *)aPort forMode:(NSRunLoopMode)mode;
[[NSRunLoop currentRunLoop] removePort:myPort forMode:NSDefaultRunLoopMode];

方法八:run
OC

- (void)run;
[myRunLoop run];

方法九:runMode:beforeDate:
OC

- (BOOL)runMode:(NSRunLoopMode)mode beforeDate:(NSDate *)limitDate;
[myRunLoop runMode:NSDefaultRunLoopMode beforeDate:[NSDate dateWithTimeIntervalSinceNow:3]];

方法十:runUntilDate:
OC

- (void)runUntilDate:(NSDate *)limitDate;
[myRunLoop runUntilDate:[NSDate dateWithTimeIntervalSinceNow:3]];

方法十一:acceptInputForMode:beforeDate:
OC

- (void)acceptInputForMode:(NSRunLoopMode)mode beforeDate:(NSDate *)limitDate;
[myRunLoop acceptInputForMode:NSDefaultRunLoopMode beforeDate:[NSDate dateWithTimeIntervalSinceNow:3]];

方法十二:performSelector:target:argument:order:modes:
Discussion:这个方法只能在主线程或者有port的子线程里运行。让方法以你安排的顺序运行。在下个runloop循环里运行。
OC

- (void)performSelector:(SEL)aSelector target:(id)target argument:(id)arg order:(NSUInteger)order modes:(NSArray *)modes;
- (void)handleMachMessage:(void *)msg {
    [[NSRunLoop currentRunLoop] performSelector:@selector(timerControl)
                                         target:self
                                       argument:nil
                                          order:2
                                          modes:[NSArray arrayWithObject:@"NSDefaultRunLoopMode"]
     ];
    [[NSRunLoop currentRunLoop] performSelector:@selector(doFireTimer:)
                                         target:self
                                       argument:@"qqq"
                                          order:1
                                          modes:[NSArray arrayWithObject:@"NSDefaultRunLoopMode"]
     ];
}

方法十三:cancelPerformSelector:target:argument:
OC

- (void)cancelPerformSelector:(SEL)aSelector target:(id)target argument:(id)arg;

方法十四:cancelPerformSelectorsWithTarget:
OC

- (void)cancelPerformSelectorsWithTarget:(id)target;

方法十五:performBlock:
Discussion:实际上 RunLoop 底层也会用到 GCD 的东西,比如 RunLoop 是用 dispatch_source_t 实现的 Timer(评论中有人提醒,NSTimer 是用了 XNU 内核的 mk_timer,我也仔细调试了一下,发现 NSTimer 确实是由 mk_timer 驱动,而非 GCD 驱动的)。但同时 GCD 提供的某些接口也用到了 RunLoop, 例如 dispatch_async()。

当调用 dispatch_async(dispatch_get_main_queue(), block) 时,libDispatch 会向主线程的 RunLoop 发送消息,RunLoop会被唤醒,并从消息中取得这个 block,并在回调 CFRUNLOOP_IS_SERVICING_THE_MAIN_DISPATCH_QUEUE() 里执行这个 block。但这个逻辑仅限于 dispatch 到主线程,dispatch 到其他线程仍然是由 libDispatch 处理的。
OC

- (void)performBlock:(void (^)(void))block;

方法十六:performInModes:block:
OC

- (void)performInModes:(NSArray *)modes block:(void (^)(void))block;

方法十七:performSelectorOnMainThread:withObject:waitUntilDone:
方法十八:performSelectorOnMainThread:withObject:waitUntilDone:modes:
方法十九:performSelector:onThread:withObject:waitUntilDone:
方法二十:performSelector:onThread:withObject:waitUntilDone:modes:
方法二十一:performSelector:withObject:afterDelay:
方法二十二:performSelector:withObject:afterDelay:inModes:
方法二十三:cancelPreviousPerformRequestsWithTarget:
方法二十四:cancelPreviousPerformRequestsWithTarget:selector:object:

你可能感兴趣的:(runloop)