Runloop的一些理解

1.Runloop与dispatch的关系

1.在__CFRunLoopRun函数中,用dispatch_source_create创建一个定时器。处理此次runLoop mode的运行时间,唤醒Runloop
2.使用dispatch的任务(main_queue中),例如
dispatch_async 提交的任务
dispatch_after 提交的延时任务
dispatch_source_create
dispatch_source_set_timer
dispatch_source_set_event_handler
设置的定时器

它们的执行流程是
BeforeSources后,开始处理提交到Runloop的Block(通过-[NSRunLoop performBlock:]方式),然后开始处理source0,如果在source0中处理了,再处理一下Block。调用__CFRunLoopServiceMachPort,在其中用循环的方式通过mach_msg接受消息,mach_msg_header_t类型的消息体的msgh_local_port来自_dispatch_get_main_queue_port_4CF函数,当有dispatch的任务时,Runloop就会接收到消息。在调用__CFRUNLOOP_IS_SERVICING_THE_MAIN_DISPATCH_QUEUE__,其内部又调用了_dispatch_main_queue_callback_4CF,最终回到dispatch库中执行任务。

堆栈调用

  * frame #0: 0x0000000103912c83 testblock`__29-[ViewController viewDidLoad]_block_invoke(.block_descriptor=0x000060000193ee20) at ViewController.m:82:10
    frame #1: 0x00000001057ef9c8 libdispatch.dylib`_dispatch_client_callout + 8
    frame #2: 0x00000001057f2316 libdispatch.dylib`_dispatch_continuation_pop + 557
    frame #3: 0x0000000105805e8b libdispatch.dylib`_dispatch_source_invoke + 2205
    frame #4: 0x00000001057fdca4 libdispatch.dylib`_dispatch_main_queue_callback_4CF + 687
    frame #5: 0x0000000104201dab CoreFoundation`__CFRUNLOOP_IS_SERVICING_THE_MAIN_DISPATCH_QUEUE__ + 9
    frame #6: 0x00000001041fc62e CoreFoundation`__CFRunLoopRun + 2685
    frame #7: 0x00000001041fb6c6 CoreFoundation`CFRunLoopRunSpecific + 567
    frame #8: 0x000000011010cdb3 GraphicsServices`GSEventRunModal + 139
    frame #9: 0x00000001079ad187 UIKitCore`-[UIApplication _run] + 912
    frame #10: 0x00000001079b2038 UIKitCore`UIApplicationMain + 101
    frame #11: 0x000000010391431a testblock`main(argc=1, argv=0x00007ffeec2eed18) at main.m:18:12
    frame #12: 0x000000010587e409 libdyld.dylib`start + 1
    frame #13: 0x000000010587e409 libdyld.dylib`start + 1

2.Runloop与定时器的关系

dispatch类型的定时器,上面已经谈过了,我们谈下其他类型的定时器,

1.NSTimer类型的

这种类型会转换为CFRunLoopTimerRef,然后加入到Runloop的mode中去,最终在__CFRunLoopDoTimers中进行触发。

2.perform类型

-[NSObject performSelector:withObject:afterDelay:]
-[NSObject performSelector:withObject:afterDelay:inModes:]

此类型和NSTimer类型一样的处理流程。

3.CADisplayLink类型

CADisplayLink必须调用-[CADisplayLink addToRunLoop:forMode:]才能生效,
这种会转换成source1,添加到Runloop中去。最终在__CFRunLoopDoSource1中,通过__CFRUNLOOP_IS_CALLING_OUT_TO_A_SOURCE1_PERFORM_FUNCTION__被调用。

3.Runloop与perform

NSThreadPerformAdditions分类中的方法

- (void)performSelectorOnMainThread:(SEL)aSelector withObject:(nullable id)arg waitUntilDone:(BOOL)wait modes:(nullable NSArray *)array;
- (void)performSelectorOnMainThread:(SEL)aSelector withObject:(nullable id)arg waitUntilDone:(BOOL)wait;

- (void)performSelector:(SEL)aSelector onThread:(NSThread *)thr withObject:(nullable id)arg waitUntilDone:(BOOL)wait modes:(nullable NSArray *)array;
- (void)performSelector:(SEL)aSelector onThread:(NSThread *)thr withObject:(nullable id)arg waitUntilDone:(BOOL)wait;
- (void)performSelectorInBackground:(SEL)aSelector withObject:(nullable id)arg ;

会在对于的thread中的Runloop添加一个基于port的source,即source1。最终在__CFRunLoopDoSources0中调用__CFRUNLOOP_IS_CALLING_OUT_TO_A_SOURCE0_PERFORM_FUNCTION__来执行selector。

你可能感兴趣的:(iOS)