【问题标题】:How to call a method a.s.a.p. but at earliest in the next run loop iteration?如何调用方法 a.s.a.p.但最早在下一次运行循环迭代中?
【发布时间】:2011-08-17 16:22:38
【问题描述】:

我需要一个保存的方式来说:“iOS,我希望这个方法能够立即执行,但不在本次运行循环迭代中。最早在下一次,但请不要在本次中。谢谢。”

现在我总是这样:

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

假设-doSomeOtherThings 将始终在之前执行 -doSomethingInNextRunLoop.

文档说:

指定延迟为 0 并不一定会导致选择器 立即执行。选择器仍然在线程的队列中 运行循环并尽快执行。

所以基本上它可能会立即调用该方法,就好像我刚刚发送了一条直接消息,导致-doSomethingInNextRunLoop-doSomeOtherThings 之前执行?

我怎样才能绝对确定它会被称为 a.s.a.p。但从来没有在同一个运行循环迭代中?

为了澄清措辞:运行循环是指主线程,以及所有方法必须返回的迭代,直到线程再次为新事件做好准备。

【问题讨论】:

    标签: iphone ios ipad nsobject performselector


    【解决方案1】:

    如果您担心 Apple 某天可能会将延迟设为 0 的特殊情况,您始终可以将延迟指定为 1e-37 左右。尽管performSelector:withObject:afterDelay: 的文档可以很容易地阅读以保证选择器将始终被安排在下一次运行循环迭代中。

    如果您担心 Apple 某天可能会在特殊情况下的延迟小于某个任意下限,您可以随时尝试使用 NSRunLoop 的 performSelector:target:argument:order:modes:,文档明确指出它将为运行循环的下一次迭代安排执行。

    【讨论】:

    • 太棒了!一个可以缓解这种情况的类别是有意义的。
    【解决方案2】:

    使用 GCD(Grand Central Dispatch)非常简单:

    dispatch_async (dispatch_get_main_queue (), ^{
        NSLog (@"This stuff runs in the next iteration of the main run loop");
    });
    

    【讨论】:

      【解决方案3】:

      我认为你阅读文档的结论是错误的。

      所以基本上它可能会立即调用该方法,就好像我刚刚发送了一条直接消息

      没有。您引用的文档部分说,无论如何,选择器总是在运行循环中排队。所以它永远不会像直接消息一样被执行。

      带有“不一定”的第一句话可能有点误导,但我认为第二句话应该真正澄清你担心的事情不会发生。

      【讨论】:

      • 希望你是对的,因为我敢打赌很多人都依赖它排队等待下一次迭代。尽管如此,还是有一些不确定性。
      【解决方案4】:

      当然你就是这样做的;

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

      这保证了你想要的执行顺序。

      【讨论】:

      • 在比这个用于说明的简单示例更复杂的情况下,以这种方式重新排列代码并不总是方便(或可能)。
      • 并非如此。在 NEXT 运行循环迭代中执行操作有充分的理由。其中之一:让 UI 在两者之间刷新。提高感知性能。在许多其他人中。除此之外,Anomie 是对的。
      • 当然,Anomie 的反应一针见血,我只是指出,在某些情况下,代码重新排列也可以解决问题。有点像作家的障碍,有时开发人员会挂起以特定方式解决问题,而实际上有一个横向计划 B。FWIW 我不知道标准 performSelector:withObject:afterDelay:0 导致的任何实例阻止并经常使用该技术来优化其他人编写的 UI 代码。
      最近更新 更多