iOS上runloop中的操作顺序
iOS上的操作顺序是什么 我在特别考虑结婚的时间iOS上runloop中的操作顺序,ios,grand-central-dispatch,nsthread,nsrunloop,Ios,Grand Central Dispatch,Nsthread,Nsrunloop,iOS上的操作顺序是什么 我在特别考虑结婚的时间 setNeedsLayout和layoutSubviews setNeedsDisplay和drawRect 触摸识别 [NSTimer scheduledTimerWithTimeInterval:0.000001 tar(…)] dispatch\u async(dispatch\u get\u main\u queue(),^{/*code*/} 作为我希望收到的答案的一个例子,可以采用以下格式: 在下一个运行周期之前在main上进行
和setNeedsLayout
layoutSubviews
和setNeedsDisplay
drawRect
- 触摸识别
[NSTimer scheduledTimerWithTimeInterval:0.000001 tar(…)]
dispatch\u async(dispatch\u get\u main\u queue(),^{/*code*/}
作为我希望收到的答案的一个例子,可以采用以下格式: 在下一个运行周期之前在main上进行异步调度 drawRect发生在运行周期结束时
一个接一个的任务从不同的源添加到runloop;runloop将在runloop上执行最早的任务,并且在对该任务的调用返回之前不会启动另一个任务
setNeedsLayout
和setNeedsDisplay
,如果它们需要更新layoutSubviews
完成布局(由layoutSublayers
间接调用)drawRect
和DrawInText:
dispatch\u async
调用已执行0.000001
秒,可以在调度\u async
之前或之后执行。很难说setNeedsLayout
和setNeedsDisplay
在某个地方引起UI的更改
1、2、3和4的顺序是明确定义的。5也应该始终发生在之后。NSTimer
取决于各种情况-您不应该依赖于它是在dispatch\u async
调用之前还是之后调用的,但它很可能会在绘制完成后执行。(部分内容是从中复制的。)
事实证明,运行循环是复杂的,像“drawRect:是否发生在运行周期结束时?”这样的简单问题没有简单的答案
CFRunLoop
是的一部分,因此我们可以查看它所包含的内容。运行循环大致如下所示:
while(true){
调用KCFRunlopBeforeTimers观察员回调;
调用kCFRunLoopBeforeSources观察器回调;
执行由CFRunLoopPerformBlock排队的块;
调用已发信号的每个版本0 CFRunLoopSource的回调;
//触摸事件是iOS 8.0中的版本0源。
//CFSocket是版本0的源代码。
if(调用了任何版本0的源回调){
执行CFRunLoopPerformBlock新排队的块;
}
如果(我在上一次迭代中没有耗尽主队列)
并且主队列中有任何等待的块)
{
从主队列中删除所有块
执行刚刚从主队列中删除的所有块
}否则{
在等待观察器回调之前调用kcfrunloop;
//核心动画使用等待前观察者执行布局和绘图。
等待CFRunLoopSource发出信号
或者让计时器启动
或将块添加到主队列中;
调用kcfrunlopafterwaiting观察器回调;
if(事件是计时器){
调用CFRunLoopTimer回调,以获取现在应该触发的计时器
}else if(事件是到达主队列的块){
从主队列中删除所有块
执行刚刚从主队列中删除的所有块
}否则{
查找事件的版本1 CFRunLoopSource
如果(我找到了版本1源){
调用源的回调函数
}
//界面方向更改是iOS 8.0版本1的源代码。
}
}
执行由CFRunLoopPerformBlock排队的块;
}
核心动画在等待之前注册一个顺序为2000000的观测者(尽管没有文档记录;您可以通过打印[nsrunlop mainlunloop].description
)来确定。此观测者提交当前的CATTransaction
,该观测者(如果需要)执行布局(updateConstraint
和LayoutSubView
)然后绘制(drawRect:
)
请注意,在执行BeforeWaiting观察器之前,运行循环可以对while(true)
中的true
求值两次。如果它分派计时器或版本1源,并且这会在主队列上放置块,则运行循环将在调用BeforeWaiting观察器之前循环两次(它将同时发送版本0源)
系统混合使用版本0源和版本1源。在我的测试中,触摸事件是使用版本0源交付的。(您可以通过在触摸处理程序中放置断点来判断;堆栈跟踪包含\u CFRunLoopDoSources0
)像进入/离开前台这样的事件是通过CFRunLoopPerformBlock
发送的,所以我不知道真正提供它们的是哪种源代码。接口方向的更改是通过版本1源代码发送的。(很可能nsursession
和nsurconnection
在内部使用CFSocket
)
请注意,运行循环是结构化的,因此在每次迭代中只有一个分支发生:
dispatch\u get\u main\u queue()
run、或