我有一个包含带循环的方法的类。如果发生某个事件(例如按下按钮),我需要能够打破循环。
当按下按钮时,我正在使用NSNotificationCenter
通知包含循环的类。
但是,如果我在执行循环时按下按钮,则通知会在循环完成后发生,而不是中断循环。
我猜这是因为它在同一个线程中运行。
那么如何NSNotificationCenter
在后台/不同线程中进行操作?这可能吗?或者有更好的方法吗?
我有一个包含带循环的方法的类。如果发生某个事件(例如按下按钮),我需要能够打破循环。
当按下按钮时,我正在使用NSNotificationCenter
通知包含循环的类。
但是,如果我在执行循环时按下按钮,则通知会在循环完成后发生,而不是中断循环。
我猜这是因为它在同一个线程中运行。
那么如何NSNotificationCenter
在后台/不同线程中进行操作?这可能吗?或者有更好的方法吗?
它不仅仅是通知中心。
我有一个包含带循环的方法的类。如果发生某个事件(例如按下按钮),我需要能够打破循环。
该按钮按下的事件进入主线程。如果您的循环在主线程上运行,那么在您的循环完成之前,按下按钮本身不会被处理。通知会立即发布,相对于您的应用程序实际处理的按钮按下。
或者,以列表形式:
您看到的延迟介于第 1 步和第 2 步之间;第 4 步在第 3 步之后立即发生。
本地(非分布式)NSNotificationCenter 上的通知在您发布它们的线程上分派,因此从您的操作方法发布它意味着它将在主线程上分派。这是正常的。
将循环而不是通知移动到后台线程、调度队列或操作队列。如果您使用操作队列,您可能根本不需要通知,因为您可以告诉操作队列取消所有挂起的操作。(您的操作需要在任何适当的时间检查它们是否已被取消;由于前面讨论的原因,在随机时间杀死线程/操作是一个坏主意。)
后台线程、块和操作可以在需要时与主线程通信(例如,更新 UI)。要通过主线程的运行循环发送消息,请使用performSelectorOnMainThread:withObject:waitUntilDone:
. 要在主线程上分派块,请使用dispatch_async
and dispatch_get_main_queue
。要在主线程上安排操作,请将其添加到[NSOperationQueue mainQueue]
.
我会在一个单独的线程中运行你的循环,并有一个实例变量BOOL abort;
,当你的按钮按下通知进来时,设置abort = TRUE;
然后在循环中检查这个值,如果它是真的就退出。
我会在一个单独的线程中运行循环。更好的是,将其设为 NSOperation 以便您可以调用[.. cancel]
. 只需确保performSelectorOnMainThread
在从 NSOperation 对象更新 UI 时使用。在主线程上有一个长时间运行的循环不是一个好主意。
您不能将通知中心放在另一个线程上。那个物体是你无法控制的。问题不在于它们在同一个线程上,而在于您不允许负责处理按钮按下的run loop执行任何操作。(每个线程只有一个运行循环。)正如 edsko 和 Peter Hosey 所说,按钮按下本身,实际上是整个 UI,在循环运行时都会停止。将长时间运行的操作放在后台线程上通常是个好主意,然后回调到主线程以更新 UI,performSelectorOnMainThread:withObject:waitUntilDone:
这是进行此类回调的一种简单方法。
也就是说,如果要将循环保留在主线程上,则需要让控制定期返回运行循环,以便注册按钮按下。我可以想到两种方法来做到这一点。首先,您可以在循环的每次迭代期间显式地给出运行循环控制:
while( !buttonWasPressed ){
// Do work...
// Let the run loop do some processing before the next iteration.
[[NSRunLoop currentRunLoop] runUntilDate:[NSDate dateWithTimeIntervalSinceNow:0.01]];
}
或者,您可以创建一个仅由循环中的代码组成的方法,并使用performSelector:withObject:afterDelay:
该方法重复调用该方法,同时仍然允许运行循环工作:
- (void) loopTheLoop {
if( buttonWasPressed ) return;
// Do work...
// Run this method again as soon as possible.
[self performSelector:@selector(loopTheLoop)
withObject:nil
afterDelay:0.0];
}