我希望能够在下一次运行循环迭代中执行block.它是在下一个运行循环的开始还是结束时执行并不重要,只是执行会推迟到当前运行循环中的所有代码都执行完毕.

我知道下面的代码不起作用,因为它与主运行循环交错,所以我的代码可能会在下一个运行循环中执行,但可能不会.

dispatch_async(dispatch_get_main_queue(),^{
    //my code
});

我认为以下问题与上述问题相同:

dispatch_after(DISPATCH_TIME_NOW, dispatch_get_main_queue(), ^(void){
    //my code
});

现在我知道,当它被放置在当前运行循环的末尾时(如果我错了,请纠正我),下面的内容会起作用吗?

[self performSelector:@selector(myMethod) withObject:nil afterDelay:0];

那么一个间隔为0的计时器呢?文档说明:If seconds is less than or equal to 0.0, this method chooses the nonnegative value of 0.1 milliseconds instead.这是否转化为保证下一次运行循环迭代的执行?

[NSTimer scheduledTimerWithTimeInterval:0 target:self selector:@selector(myMethod) userInfo:nil repeats:NO];

这是我能想到的所有选项,但我仍然无法在下一次运行循环迭代中执行一个块(而不是调用一个方法),并保证它不会更快.

推荐答案

您可能不知道运行循环在每个迭代中所做的一切.(在我研究这个答案之前,我不是!)事实上,CFRunLoopopen-source CoreFoundation package的一部分,所以我们可以看看它到底意味着什么.运行循环大致如下所示:

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 signalled;
    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)
    {
        while (main queue has blocks) {
            perform the next block on the main queue
        }
    } else {
        Call kCFRunLoopBeforeWaiting observer callbacks;
        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) {
            while (main queue has blocks) {
                perform the next block on 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
            }
        }
    }
    Perform blocks queued by CFRunLoopPerformBlock;
}

您可以看到,有多种方法可以连接到run循环中.你可以为任何你想要的"活动"创建一个CFRunLoopObserver.您可以创建一个版本0 CFRunLoopSource并立即发送信号.您可以创建一对连接的CFMessagePorts,将其中一个封装在版本1 CFRunLoopSource中,并向其发送消息.你可以创建一个CFRunLoopTimer.您可以使用dispatch_get_main_queueCFRunLoopPerformBlock对块进行排队.

您需要根据何时调度块以及何时需要调用块来决定使用这些API中的哪一个.

例如,touch 是在版本1源中处理的,但如果通过更新屏幕来处理touch ,则在提交核心动画事务之前,不会实际执行该更新,而核心动画事务是在kCFRunLoopBeforeWaiting个观察者中发生的.

现在假设您希望在处理touch 时安排块,但希望在事务提交后执行.

您可以为kCFRunLoopBeforeWaiting活动添加自己的CFRunLoopObserver,但此观察者可能会在核心动画的观察者之前或之后运行,具体取决于您指定的顺序和核心动画指定的顺序.(Core Animation目前指定的订单为2000000,但没有记录,因此可能会发生变化.)

要确保块在核心动画的观察者之后运行,即使观察者运行before核心动画的观察者,也不要在观察者的回调中直接调用块.相反,此时使用dispatch_async将块添加到主队列中.将块放在主队列上将迫使运行循环立即从其"等待"中唤醒.然后你的观察者会在任何时候阻塞你的主队列.

Objective-c相关问答推荐

如何使用名称而不是self.name?访问Deliver-C @Property

当我们只能使用 NSObject 时,为什么还要使用 id?

在哪里可以找到 iPad 示例代码

iphone - 防止uiscrollview通过滚动

iOS 心率检测算法

如果用户点击屏幕键盘,我如何关闭键盘?

如何将 UInt32 设置为最大值

BSXPCMessage 收到消息错误:连接中断

如何知道 NSAssert 在发布版本中是否被禁用?

判断用户是否在连续的 UISlider 上完成滑动?

更改后退导航栏按钮的字体

Apple 的 API 中的k前缀表示什么?

奇怪的错误 NSAssert

NSManagedObjectContext:异常断点在 save: 方法处停止,但没有日志(log)/崩溃/错误

在字符串Objective-c中连接字符串

如何从设置屏幕打开位置服务屏幕?

交换 NSMutableArray 中的元素

Objective-c 2.0 中的可选参数?

UIImage上的圆角

如何设置字体大小以填充 UILabel 高度?