是否有一种简单的方法(在Cocoa/iOS中)将方法调用排队以在下一个运行循环中运行一次?

Kri*_*ins 13 cocoa cocoa-touch objective-c ios

UIView有一个setNeedsDisplay方法,可以在同一个事件循环中多次调用,安全知道重绘工作很快就会发生,而且只有一次.

Cocoa有这种行为的通用机制吗?一种说法,"按照你喜欢的方式多次排队一个选择器,当它的时候,选择器将运行一次并清除队列."

我知道我可以通过目标中的某种状态跟踪或使用NSOperationQueue来执行此操作.我只是想知道是否有一种我错过的轻量级方法.

(当然,答案可能是"不".)

Rob*_*ier 12

setNeedsDisplay并不是你所描述的一个很好的例子,因为它实际上每次调用时都会运行.它只是设置了一面旗帜.但问题是好的.

一个解决方案是使用NSNotificationQueueNSNotificationCoalescingOnName.

另一个解决方案是建立一个蹦床来自己进行合并.我没有关于蹦床的真正好的博客参考,但这里有一个例子(LSTrampoline).如果你想在一段时间内合并消息,那么构建它并不困难.我曾经建造过一个forwardInvocation:类似于此的蹦床:

- (void)forwardInvocation:(NSInvocation *)invocation {
  [invocation setTarget:self.target];
  [invocation retainArguments];
  [self.timer invalidate];
  self.timer = [NSTimer scheduledTimerWithTimeInterval:self.timeout invocation:invocation repeats:NO];
}
Run Code Online (Sandbox Code Playgroud)

这实际上会在一段时间内将所有消息合并到对象(而不仅仅是匹配消息).这就是我对特定问题所需要的一切.但您可以对此进行扩展以跟踪正在合并的选择器,并检查您的调用以查看它们是否"足够"匹配.

要使其在下一个事件循环上运行,只需将timeout设置为0.

关于蹦床的博客,我一直有意思.要求先令:我即将出版的书涵盖了第4章和第20章中的蹦床.

  • 很棒的答案,我认为NSNotificationCoalescingOnName正是我想要的.:-) (2认同)

omz*_*omz 6

[NSObject cancelPreviousPerformRequestsWithTarget:self 
                                         selector:@selector(doTheThing:)
                                           object:someObject];
[self performSelector:@selector(doTheThing:) 
           withObject:someObject 
           afterDelay:0];
Run Code Online (Sandbox Code Playgroud)

这并不是UIView这样做的原因,因为setNeedsDisplay只需设置一个标志,内部UIView机制确保drawRect:在设置绘图环境后调用,但这是一种通用的方式,并且不需要在类中进行任何特殊的状态跟踪.