hfo*_*sli 7 nsthread grand-central-dispatch nsrunloop ios
iOS上的操作顺序是什么?
我正在考虑时间问题
setNeedsLayout 和 layoutSubviewssetNeedsDisplay 和 drawRect[NSTimer scheduledTimerWithTimeInterval:0.000001 tar(...)]dispatch_async(dispatch_get_main_queue(), ^{ /* code */}作为我希望收到的答案的一个例子,它可以采用以下格式:
main上的dispatch_async 在下一个运行周期之前发生
drawRect 在运行周期结束时发生
rob*_*off 23
(部分内容是从我对类似问题的回答中复制而来的.)
事实证明,运行循环很复杂,并且一个简单的问题,例如"在运行drawRect:周期结束时会发生吗?"并没有一个简单的答案.
CFRunLoop是开源CoreFoundation包的一部分,所以我们可以看看它究竟是什么.运行循环看起来大致如下:
while (true) {
Call kCFRunLoopBeforeTimers observer callbacks;
Call kCFRunLoopBeforeSources observer callbacks;
Perform blocks queued by CFRunLoopPerformBlock;
Call the callback of each version 0 CFRunLoopSource that has been signaled;
// Touch events are a version 0 source in iOS 8.0.
// CFSocket is a version 0 source.
if (any version 0 source callbacks were called) {
Perform blocks newly queued by CFRunLoopPerformBlock;
}
if (I didn't drain the main queue on the last iteration
AND the main queue has any blocks waiting)
{
remove all blocks from the main queue
execute all the blocks just removed from the main queue
} else {
Call kCFRunLoopBeforeWaiting observer callbacks;
// Core Animation uses a BeforeWaiting observer to perform layout and drawing.
Wait for a CFRunLoopSource to be signalled
OR for a timer to fire
OR for a block to be added to the main queue;
Call kCFRunLoopAfterWaiting observer callbacks;
if (the event was a timer) {
call CFRunLoopTimer callbacks for timers that should have fired by now
} else if (event was a block arriving on the main queue) {
remove all blocks from the main queue
execute all the blocks just removed from the main queue
} else {
look up the version 1 CFRunLoopSource for the event
if (I found a version 1 source) {
call the source's callback
}
// Interface orientation changes are a version 1 source in iOS 8.0.
}
}
Perform blocks queued by CFRunLoopPerformBlock;
}
Run Code Online (Sandbox Code Playgroud)
Core Animation注册一个kCFRunLoopBeforeWaiting2000000订单的观察者(虽然没有记录;你可以通过打印来计算出来[NSRunLoop mainRunLoop].description).该观察者提交当前的电流CATransaction(如果需要)执行布局(updateConstraints和layoutSubviews)然后绘制(drawRect:).
需要注意的是运行循环可以评估true在while(true)执行BeforeWaiting观察家之前的两倍.如果它调度计时器或版本1源,并且将块放在主队列上,则运行循环将在调用BeforeWaiting观察者之前四次运行(并且它将两次调度版本0源).
系统使用版本0源和版本1源的混合.在我的测试中,触摸事件使用版本0源提供.(您可以通过在触摸处理程序中放置断点来判断;堆栈跟踪包含__CFRunLoopDoSources0.)通过调度输入/离开前景等事件CFRunLoopPerformBlock,因此我不知道哪种类型的源实际提供了它们.界面方向更改通过版本1源提供. CFSocket记录为版本0源.(这可能是因为NSURLSession和NSURLConnection使用CFSocket内部.)
请注意,运行循环是结构化的,因此每次迭代时只会发生其中一个分支:
dispatch_get_main_queue()运行,或之后,任意数量的版本0源都可以调用它们的回调.
所以:
另请记住,您可以随时使用请求立即布局layoutIfNeeded.
| 归档时间: |
|
| 查看次数: |
1332 次 |
| 最近记录: |