美文网首页
iOS Runloop 问题总结

iOS Runloop 问题总结

作者: __SanJi | 来源:发表于2018-01-16 17:19 被阅读17次

    1、什么是runloop, 用来做什么的?

    一个线程执行一次任务,当任务执行完毕以后,线程就会被退出,所以我们需要一种机制可以让线程在执行任务完毕以后不退出,这种机制就是Runloop

    2、Runloop跟线程有什么关系?

    线程和 RunLoop 之间是一一对应的,其关系是保存在一个全局的 Dictionary 里。线程刚创建时并没有 RunLoop,如果你不主动获取,那它一直都不会有。RunLoop 的创建是发生在第一次获取时,RunLoop 的销毁是发生在线程结束时。你只能在一个线程的内部获取其 RunLoop(主线程除外)。

    3、Runloop有几种mode?

    两种:defaultRunloopMode 跟 trackingRunloopMode,defaultRunloopMode是App平时所处的mode, TrackingRunLoopMode 是追踪 ScrollView 滑动时的状态,当你创建一个 Timer 并加到 DefaultMode 时,Timer 会得到重复回调,但此时滑动一个TableView时,RunLoop 会将 mode 切换为 TrackingRunLoopMode,这时 Timer 就不会被回调,并且也不会影响到滑动操作。

    4、苹果是如何实现autoReleasePool的?

    app在启动的时候在主线程的runloop创建了两个observer,回调都是_wrapRunLoopWithAutoreleasePoolHandler()

    第一个observer监听的是entry事件,其回调内会调用 _objc_autoreleasePoolPush() 创建自动释放池。其 order 是-2147483647,优先级最高,保证创建释放池发生在其他所有回调之前。

    第二个 Observer 监视了两个事件: BeforeWaiting(准备进入休眠) 时调用_objc_autoreleasePoolPop() 和 _objc_autoreleasePoolPush() 释放旧的池并创建新池;Exit(即将退出Loop) 时调用 _objc_autoreleasePoolPop() 来释放自动释放池。这个 Observer 的 order 是 2147483647,优先级最低,保证其释放池子发生在其他所有回调之后。在主线程执行的代码,通常是写在诸如事件回调、Timer回调内的。这些回调会被 RunLoop 创建好的 AutoreleasePool 环绕着,所以不会出现内存泄漏,开发者也不必显示创建 Pool 了。

    5、跟GCD有什么关系?

    实际上 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 处理的。

    参考ibireme大神的文章: 深入理解RunLoop

    相关文章

      网友评论

          本文标题:iOS Runloop 问题总结

          本文链接:https://www.haomeiwen.com/subject/mzteoxtx.html