关于RunLoop的几个问题

1.界面刷新时,在什么时候真正执行刷新,为什么会刷新不及时?

当UIView/CALayer相关的属性发生了变化,或者手动调用了setNeedsLayout/setNeedsDisplay的方法时,UIView/CALayer就会被标记为待处理,放在一个全局的容器里。

苹果注册了一个Observer来监听RunLoop的BeforeWaiting状态和Exit状态。当RunLoop处于这样的状态时,就会去调用一个很长的函数来遍历所有的待处理的UIView/CALayer,然后进行实际的绘制和调整,并刷新界面。

2.项目执行过程中,总是有释放池的创建与销毁,这些是在什么时候发生的?

应用启动后,苹果会在主线程注册两个Observer, 回调都是_wrapRunLoopWithAutoreleasePoolHandler()。

a.第一个Observer 监听的是Enter,其回调会调用 _objc_autoreleasePoolPush()来创建自动释放池,并且Order = -2147483647,优先级最高。所以自动释放池的创建会发生在所有回调之前。

b.第二个Observer监听的是BeforeWaiting和Exit。BeforeWaiting会调用_objc_autoreleasePoolPop() 和 _objc_autoreleasePoolPush() 释放旧的释放池,并创建新的释放池。Exit会调用_objc_autoreleasePoolPop() 来释放自动释放池。Order = 2147483647,优先级最低。所以,销毁释放池发生在所有操作之后。

ps:在主线程执行的代码,通常是写在事件回调,Timer回调内的。而这些回调会被放在RunLoop内的自动释放池AutoreleasePool里。所以不会出现内存泄漏,一般不用再创建AutoreleasePool了。

3.事件响应和手势识别 底层处理是一样的吗?为什么?

手势识别只是事件响应事件的一种。

a.事件响应:

苹果注册了一个 Source1 (基于 mach port 的) 用来接收系统事件,其回调函数为 __IOHIDEventSystemClientQueueCallback()。

当一个硬件事件(触摸/锁屏/摇晃等)发生后,首先由 IOKit.framework 生成一个 IOHIDEvent 事件并由 SpringBoard 接收。SpringBoard 只接收按键(锁屏/静音等),触摸,加速,接近传感器等几种 Event,随后用 mach port 转发给需要的App进程。随后苹果注册的那个 Source1 就会触发回调,并调用 _UIApplicationHandleEventQueue() 进行应用内部的分发。

_UIApplicationHandleEventQueue() 会把 IOHIDEvent 处理并包装成 UIEvent 进行处理或分发,其中包括识别 UIGesture/处理屏幕旋转/发送给 UIWindow 等。通常事件比如 UIButton 点击、touchesBegin/Move/End/Cancel 事件都是在这个回调中完成的。

b.手势识别:

当上面的 _UIApplicationHandleEventQueue() 识别了一个手势时,其首先会调用 Cancel 将当前的 touchesBegin/Move/End 系列回调打断。随后系统将对应的 UIGestureRecognizer 标记为待处理。

苹果注册了一个 Observer 监测 BeforeWaiting (Loop即将进入休眠) 事件,这个Observer的回调函数是 _UIGestureRecognizerUpdateObserver(),其内部会获取所有刚被标记为待处理的 GestureRecognizer,并执行GestureRecognizer的回调。

当有 UIGestureRecognizer 的变化(创建/销毁/状态改变)时,这个回调都会进行相应处理。


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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值