iOS RunLoop简介

1.RunLoop和线程的关系?

(1)一个线程对应一个RunLoop;

(2)主线程默认有一个RunLoop;

(3)子线程的RunLoop以懒加载的形式创建;

(4)RunLoop存储在一个全局的可变字典里,线程是key,RunLoop是value;

2.RunLoop的运行模式

RunLoop的运行模式共有5种,RunLoop只会运行在一个模式下,要切换模式,就要暂停当前模式,重新启动一个运行模式

1. kCFRunLoopDefaultMode:App的默认Mode,通常主线程是在这个Mode下运行
2. UITrackingRunLoopMode:界面跟踪 Mode,用于 ScrollView 追踪触摸滑动,保证界面滑动时不受其他 Mode 影响
3. UIInitializationRunLoopMode: 在刚启动 App 时第进入的第一个 Mode,启动完成后就不再使用
4. GSEventReceiveRunLoopMode: 接受系统事件的内部 Mode,通常用不到
5. kCFRunLoopCommonModes: 这是一个占位用的Mode,作为标记kCFRunLoopDefaultMode和UITrackingRunLoopMode用,并不是一种真正的Mode.

3.RunLoop的内部逻辑

实际上RunLoop就是一个do-while循环函数,当你调用CFRunLoopRun()时,线程就会一直停留在循环里;直到超时或被手动停止,该函数才会返回。

内部逻辑:

(1)通知Observer已经进入了RunLoop;

(2)通知Observer即将处理Timer;

(3)通知Observer即将处理非基于端口的输入源(即将处理Source0);

(4)处理那些准备好的非基于端口的输入源(处理Source0);

(5)如果基于端口的输入源准备就绪并等待处理,请立即处理该事件。转到第9步,处理Source1;

(6)通知Observer线程即将休眠;

(7)将线程置于休眠状态,直至发生以下事件之一

  • 事件到达基于端口的输入源
  • Timer到时间执行
  • 外部手动唤醒
  • 为RunLoop设置的时间超时

(8)通知observer线程刚被唤醒(还没处理事件)

(9)处理待处理事件

  • 如果谁Timer事件,处理Timer并重新启动循环,跳转到第2步
  • 如果输入源被触发,处理该事件
  • 如果RunLoop被手动唤醒且尚未超时,重新启动循环,跳转到第2步

4.autoReleasePool在何时被释放?

(1)APP启动后,苹果在主线的RunLoop里面注册了两个Observer,其回调都是_wrapRunLoopWithAutoreleasePoolHandler()。

(2)第一个Observer监听的事件是Entry(即将进入Loop),其回调内会调用-objc_autoreleasePoolPush()创建自动释放池。其优先级最高,保证创建释放池发生在其他所有回调之前。

(3)第二个Observer监听了两件事:BeforeWaiting(准备进入休眠)时调用_objc_autoreleasePoolPop()和_objc_autoreleasePoolPush()释放旧的池并创建新池;Exit(即将推出Loop)时调用_objc_autoreleasePoolPop()来释放自动释放池。此时Observer的优先级最低,保证其释放池发生在其他所有回调之后。

(4)在主线程执行的代码,通常是写在诸如事件回调、Timer回调内的。这些回调会被RunLoop创建好的AutoreleasePool环绕着,所以不会出现内存泄漏,开发者不必显示创建Pool.

5.GCD在RunLoop中的使用?

GCD由子线程返回到主线程,只有在这种情况下才会触发RunLoop(会触发RunLoop的Source1事件)。

6.performSelector的实现原理?

(1)当调用NSObejct的performSelector:afterDelay:后,实际上其内部会创建一个Timer并添加到当前线程的RunLoop中,所以如果当前线程没有RunLoop,则这个方法会失效;

(2)当调用performSelector:onThread:的时候,实际上其会创建一个Timer加到对应的线程中,同样的,如果对应线程没有RU nLoop该方法也会失效。

7.CADisplayLink和NSTimer哪个更准确?

CADisPlayLink相对更加准确

(1)iOS的屏幕刷新频率是固定的,CADisplayLink咋正常情况下会在每次刷新结束后都会被调用,精准度相当高(如果CPU操作饱和,影响了屏幕刷新,也会影响计时器的精准。

(2)NSTimer的精确度就显得低了点,比如NSTimer的触发时间到的时候,runloop如果在阻塞状态,触发时间就会推迟到下一个runloop周期。并且 NSTimer新增了tolerance属性,让用户可以设置可以容忍的触发的时间的延迟范围。

(3)CADisplayLink使用场合相对专一,适合做UI的不停重绘,比如自定义动画引擎或者视频播放的渲染。NSTimer的使用范围要广泛的多,各种需要单次或者循环定时处理的任务都可以使用。在UI相关的动画或者显示内容使用 CADisplayLink比起用NSTimer的好处就是我们不需要在格外关心屏幕的刷新频率了,因为它本身就是跟屏幕刷新同步的。

 

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值