将选择器加入到运行循环中 - [NSObject PerformSelector:withObject:afterDelay:] 是正确的方法吗?
我希望在当前方法通过并且 UI 已更新后执行一个方法。为此,我现在正在使用 [object PerformSelector:@selector(someSelector) withObject:someObject afterDelay:0.0]
。根据 Apple 的文档,这会创建NSTimer 将触发选择器并将其附加到当前 NSRunLoop。但我不认为这很优雅。有没有一种简单的方法可以直接将选择器排入当前运行循环,而不需要 Cocoa 创建计时器等?
会 performSelectorOnMainThread:withObject:waitUntilDone:
(如果我在主线程上)或 performSelector:onThread:withObject:waitUntilDone:
与 waitUntilDone:NO
> 以更少的开销做我想做的事?
提前欢呼并感谢
MrMage
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。
绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论
评论(5)
Cocoa 是事件驱动的。您不会“在当前运行循环中将选择器排入队列”。简而言之:发送到应用程序的事件(用户输入、计时器、网络活动...)会导致运行循环运行,从而导致循环运行中发生一些事情。当然还有“细节”,但这是最基本的行为。
如果您想推迟执行某些选择器到当前运行循环的末尾,请最后调用它,或者要求它在(非常接近)即将到来的循环运行中运行。 -performSelector:... 方法是执行此操作的正确方法。他们创建一个计时器,该计时器会产生一个导致事情发生的事件。
有关详细信息,请参阅 Cocoa 事件处理指南。
Cocoa is event-driven. You don't "enqueue a selector within the current run loop". To put it simplistically: An event sent to the application (user input, a timer, network activity ...) causes the run loop to run, which causes things to happen in that run of the loop. There are of course "details", but this is the most basic behavior.
If you want to put off performing some selector to the end of the current run loop, call it last, or ask it to be run on a (very near) upcoming run of the loop. The -performSelector:... methods are the correct way to do this. They create a timer which results in an event which causes things to happen.
For more information, see the Cocoa Event-Handling Guide.
我没有看到您突出显示的 -performSelector:withObject:afterDelay: 方法有任何不优雅的地方。此方法只是将要在运行循环的当前周期完成后执行的任务放入队列。来自您链接到的部分中的文档:
不会创建 NSTimer 对象来管理此操作,选择器只是排队等待一定延迟后运行(小延迟意味着在运行循环周期完成后立即运行)。对于您希望在 UI 更新后执行的操作,这是最简单的技术。
对于更明确的线程队列,您可以查看 NSOperations 和 NSOperationQueues 。 maxConcurrentOperationCount 为 1 的 NSOperationQueue 可以按顺序运行操作,一个接一个。
I don't see anything inelegant about the -performSelector:withObject:afterDelay: method that you highlight. This method simply enqueues a task to be performed after the completion of the current cycle of the run loop. From the documentation in the section you linked to:
An NSTimer object is not created to manage this, the selector is simply enqueued to be run after a certain delay (a small delay means immediately after the completion of the run loop cycle). For actions that you wish to happen after updates to the UI take place, this is the simplest technique.
For more explicit, threaded queueing, you could look at NSOperations and NSOperationQueues. An NSOperationQueue with a maxConcurrentOperationCount of 1 can run operations in order, one after the other.
我更喜欢 NSRunLoop 方法“performSelector:target:argument:order:modes:”。它保证在运行循环的下一次迭代之前不会执行选择器,并且您不必胡乱指定任意延迟等。
I prefer the NSRunLoop method "performSelector:target:argument:order:modes:". It's guaranteed to not execute the selector until the next iteration of the run loop, and you don't have to mess around with specifying arbitrary delays, etc.
我自己多次使用过这种技术,而且我不认为它有那么不雅...但是,您可以尝试的另一种选择是:
performSelectorOnMainThread:withObject:waitUntilDone:NO
。仅仅因为您已经在主线程上,并不意味着它不起作用(事实上,文档引用了从主线程调用时会发生的行为)...并且我认为设置 waitUntilDone 时它会具有相同的行为为 NO,它将执行选择器的请求排队,并在当前运行循环结束时运行它。
I have used this technique many times myself, and I don't think it's that inelegant... however, an alternative you could try is:
performSelectorOnMainThread:withObject:waitUntilDone:NO
.Just because you are already on the main thread, does not mean it would not work (in fact the documents reference behaviour that will happen when called from the main thread)... and I think it would have the same behavior when waitUntilDone is set to NO, where it queues up the request to execute the selector and have it run when the current run-loop ends.
只是为了完整起见,我想添加这个解决方案,如果我们想挑剔的话,这将是合适的解决方案;)
Just for completeness sake I'd like to add this solution, which would be the appropriate one if we want to be nitpicking ;)