使用 GCD 调度队列。它自动提供 FIFO 排序和块。虽然您无法取消已经在运行的请求,但您可以阻止其他请求运行。
由于您没有说您正在使用 CoreData,并且您已经在使用单独的线程,因此我假设您没有使用 CoreData 作为您的“数据库”。
尝试一些简单的事情,例如...
当你的类初始化时创建你的队列(或者应用程序启动,如果它总是应该在那里)......
dispatch_queue_t workQ = dispatch_queue_create("label for your queue", 0);
并在您的班级解除分配(或其他适当的时间)时释放它......
dispatch_release(workQ);
为了获得类似的取消,如果已经做出了另一个选择,你可以做一些简单的事情,比如使用一个令牌来查看你正在处理的请求是否是“最新的”,或者从那时起是否有另一个请求出现......
static unsigned theWorkToken;
unsigned currentWorkToken = ++theWorkToken;
dispatch_async(workQ, ^{
// Check the current work token at each step, to see if we should abort...
if (currentWorkToken != theWorkToken) return;
MyData *data = queryTheDatabaseForData(someQueryCriteria);
if (currentWorkToken != theWorkToken) return;
[data doTimeConsumingProcessing];
for (Foo *foo in [data foo]) {
if (currentWorkToken != theWorkToken) return;
// Process some foo object
}
// Now, when ready to interact with the UI...
if (currentWorkToken != theWorkToken) return;
dispatch_async(dispatch_get_main_queue(), ^{
// Now you are running in the main thread... do anything you want with the GUI.
});
});
该块将“捕获”堆栈变量“currentWorkToken”及其当前值。请注意,解锁检查在这里很好,因为您不需要跟踪连续计数,只要它在您设置后发生了变化。在最坏的情况下,您将执行额外的步骤。
如果您使用 CoreData,您可以使用 NSPrivateQueueConcurrencyType 创建您的 MOC,现在您根本不需要创建工作队列,因为私有 MOC 有自己的...
static unsigned theWorkToken;
unsigned currentWorkToken = ++theWorkToken;
[managedObjectContext performBlock:^{
// Check the current work token at each step, to see if we should abort...
if (currentWorkToken != theWorkToken) return;
MyData *data = queryTheDatabaseForData(someQueryCriteria);
if (currentWorkToken != theWorkToken) return;
[data doTimeConsumingProcessing];
for (Foo *foo in [data foo]) {
if (currentWorkToken != theWorkToken) return;
// Process some foo object
}
// Now, when ready to interact with the UI...
if (currentWorkToken != theWorkToken) return;
dispatch_async(dispatch_get_main_queue(), ^{
// Now you are running in the main thread... do anything you want with the GUI.
});
}];
GCD/Blocks 确实是这类东西的首选方法。
编辑
为什么首选?嗯,首先,使用块可以让你的代码保持本地化,而不是分散到另一个类(NSOperation)的其他方法中。还有很多其他的原因,但我将把我的个人原因放在一边,因为我不是在谈论我的个人喜好。我说的是苹果的。
只需坐一个周末,观看所有 WWDC 2011 视频。去吧,真的是大快人心。我是真诚的。如果您在美国,您将迎来一个长周末。我敢打赌,你想不出更好的办法……
不管怎样,看看这些视频,看看你能不能数出不同的演讲者说他们强烈推荐使用 GCD 的次数......和块......(以及仪器作为另一个)。
现在,WWDC 2012 可能很快就会改变,但我对此表示怀疑。
具体来说,在这种情况下,它也是比 NSOperation 更好的解决方案。是的,您可以取消尚未开始的 NSOperation。哎呀。NSOperation 仍然没有提供一种自动方式来取消已经开始执行的操作。您必须继续检查 isCanceled,并在发出取消请求时中止。因此,所有那些 if (currentToken != theWorkToken) 仍然必须像 ([self isCancelled]) 一样存在。是的,后者更容易阅读,但您还必须明确取消未完成的操作。
对我来说,GCD/blocks 解决方案更容易理解,是本地化的,并且(如所示)具有隐式取消语义。NSOperation 唯一的优点是,如果排队的操作在开始之前被取消,它会自动阻止它运行。但是,您仍然必须提供自己的取消运行操作功能,因此我认为 NSOperation 没有任何好处。
NSOperation 有它的位置,我可以立即想到几个我更喜欢它而不是直接 GDC 的地方,但对于大多数情况,尤其是这种情况,它是不合适的。