Warning: file_get_contents(/data/phpspider/zhask/data//catemap/9/ios/104.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
iOS上runloop中的操作顺序_Ios_Grand Central Dispatch_Nsthread_Nsrunloop - Fatal编程技术网

iOS上runloop中的操作顺序

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上进行

iOS上的操作顺序是什么

我在特别考虑结婚的时间

  • 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上执行最早的任务,并且在对该任务的调用返回之前不会启动另一个任务

  • 用户交互的处理
  • UI组件调用
    setNeedsLayout
    setNeedsDisplay
    ,如果它们需要更新
  • 使用
    layoutSubviews
    完成布局(由
    layoutSublayers
    间接调用)
  • 使用
    drawRect
    DrawInText:
  • dispatch\u async
    调用已执行
  • 您的计时器延迟
    0.000001
    秒,可以在
    调度\u async
    之前或之后执行。很难说
  • 1和2实际上是混合的,因为主要是用户交互通过调用
    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、
  • 一个单一的版本1源被分派到其回调
  • 之后,任何数量的版本0源都可以调用它们的回调

    因此:

  • 如果核心动画观察者运行时两者都处于挂起状态,则布局总是在绘制之前进行。CA观察者在计时器、主队列块或外部事件调用B之后运行