【问题标题】:Enqueue a selector to the run loop - is [NSObject performSelector:withObject:afterDelay:] the way to go?将选择器排入运行循环 - [NSObject performSelector:withObject:afterDelay:] 是要走的路吗?
【发布时间】:2009-11-14 16:14:59
【问题描述】:

我希望在当前方法通过并且 UI 已更新后执行一个方法。为此,我现在使用[object performSelector:@selector(someSelector) withObject:someObject afterDelay:0.0]。根据Apple's documentation,这会创建一个 NSTimer,然后它将触发选择器并将其附加到当前的 NSRunLoop。但我不认为这很优雅。有没有一种简单的方法可以直接将选择器排入当前运行循环,而无需 Cocoa 创建 Timer 等?

performSelectorOnMainThread:withObject:waitUntilDone:(如果我在主线程上)或performSelector:onThread:withObject:waitUntilDone:waitUntilDone:NO 会以更少的开销做我想做的事吗?

提前致谢

魔法师

【问题讨论】:

    标签: iphone objective-c cocoa cocoa-touch runloop


    【解决方案1】:

    Cocoa 是事件驱动的。您不会“在当前运行循环中将选择器排入队列”。简单地说:发送到应用程序的事件(用户输入、计时器、网络活动......)会导致运行循环运行,这会导致循环运行中发生事情。当然有“细节”,但这是最基本的行为。

    如果您想推迟执行某些选择器到当前运行循环的末尾,请最后调用它,或者要求它在(非常接近)即将到来的循环运行时运行。 -performSelector:... 方法正确的方法来做到这一点。他们创建了一个计时器,该计时器导致事件发生,从而导致事情发生。

    有关详细信息,请参阅Cocoa Event-Handling Guide

    【讨论】:

    • 我引用的文档显示“在下一个运行循环周期和可选的延迟期之后,在当前线程上执行指定的选择器。”这是否意味着选择器必须以某种方式排入下一个运行循环周期?
    • 当然可以。 :-) 那是通过计时器触发的事件。
    • 接受了这个,因为它让我对真正发生的事情有了最深入的了解。
    【解决方案2】:

    我没有看到您强调的 -performSelector:withObject:afterDelay: 方法有任何不雅之处。这个方法只是简单地将一个任务排入队列,在当前的run loop循环完成后执行。来自documentation in the section you linked to

    在 下一次运行期间的当前线程 循环周期和可选延迟后 时期。因为要等到 下一个运行循环周期来执行 选择器,这些方法提供了一个 从自动迷你延迟 当前正在执行的代码。多 排队的选择器被执行一个 一个接一个地按照他们的顺序 排队。

    一个 NSTimer 对象不是为了管理这个而创建的,选择器只是在一定的延迟后排队运行(小的延迟意味着在运行循环周期完成后立即运行)。对于您希望在 UI 更新后发生的操作,这是最简单的技术。

    对于更明确的线程队列,您可以查看NSOperationsNSOperationQueues。 maxConcurrentOperationCount 为 1 的 NSOperationQueue 可以按顺序运行操作,一个接一个。

    【讨论】:

    • 它确实创建了一个计时器:developer.apple.com/mac/library/documentation/cocoa/reference/…:This method sets up a timer to perform the aSelector message on the current thread’s run loop. The timer is configured to run in the default mode (NSDefaultRunLoopMode). When the timer fires, the thread attempts to dequeue the message from the run loop and perform the selector.
    • 你们都说得对。 -performSelector:withObject:afterDelay:使用核心基础计时器 API,而不是 NSTimer 实例。
    • 只是想补充一点,看起来相似的 [self performSelector: withObject:] 不会等到运行循环的下一次运行,而是立即调用该方法。很明显,但我还是把它放在那里。
    【解决方案3】:

    我更喜欢 NSRunLoop 方法“performSelector:target:argument:order:modes:”。保证在运行循环的下一次迭代之前不会执行选择器,并且您不必乱指定任意延迟等。

    【讨论】:

      【解决方案4】:

      我自己已经多次使用过这种技术,我认为它并没有那么不雅......但是,您可以尝试的替代方法是:

      performSelectorOnMainThread:withObject:waitUntilDone:NO.

      仅仅因为您已经在主线程上,并不意味着它不起作用(实际上文档引用了从主线程调用时会发生的行为)......我认为它会在waitUntilDone 设置为 NO,它将执行选择器的请求排队并在当前运行循环结束时运行。

      【讨论】:

      • 嗯,我很抱歉 - 我想我最后错过了。这是做你想做的事情的更好方法。
      【解决方案5】:

      为了完整起见,我想添加这个解决方案,如果我们想要吹毛求疵,这将是合适的解决方案;)

      [[NSOperationQueue currentQueue] addOperationWithBlock:^{
          // will be with you in a moment...
      }];
      

      【讨论】:

        猜你喜欢
        • 1970-01-01
        • 2021-12-14
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 2011-11-10
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        相关资源
        最近更新 更多