iOS 3.x中GCD串行调度队列的等价物

苹果的Grand Central Dispatch(GCD)非常棒,但只适用于iOS 4.0或更高版本。 苹果公司的文档说:“串行化操作队列不能提供与Grand Central Dispatch中的串行调度队列完全相同的行为(因为队列不是FIFO,而是由相关性和优先级决定)。

在GCD发布之前支持操作系统版本的同时,达到GCD串行调度队列的正确方法是什么? 或者换一种说法,在想要支持小于4.0版本的iOS应用程序中处理简单后台处理(执行Web服务请求等)的推荐方式是什么?

似乎人们正在努力重写NSRunloop。 根据NSRunloop文档 :

您的应用程序不能创build或显式pipe理NSRunLoop对象。 每个NSThread对象(包括应用程序的主线程)都根据需要自动创build一个NSRunLoop对象。

所以这个微不足道的答案肯定会是,创build一个可用的队列:

- (void)startRunLoop:(id)someObject { NSAutoreleasePool *pool = [[NSAutoreleasePool alloc] init]; [[NSRunLoop currentRunLoop] run]; [pool release]; } ... NSThread *serialDispatchThread = [[NSThread alloc] initWithTarget:self selector:@selector(startRunLoop:) object:nil]; [serialDispatchThread start]; 

将任务添加到队列中:

 [object performSelector:@selector(whatever:) onThread:serialDispatchThread withObject:someArgument waitUntilDone:NO]; 

根据Run Loops的线程编程指南部分 :

cocoa定义了一个自定义的input源,允许你在任何线程上执行一个select器。 …执行select器请求在目标线程上被序列化,减轻了在一个线程上运行多个方法时可能发生的许多同步问题。

所以你有一个明确的串行队列。 当然,我并不是非常写意的,因为我已经告诉运行循环永远运行,而且你可能更喜欢一个可以稍后终止的运行循环,但是这些很容易修改。

那这个PseudoSerialQueue呢? 这是一个像Dispatch Serial Queue这样的最小实现。

 #import <Foundation/Foundation.h> @interface PseudoTask : NSObject { id target_; SEL selector_; id queue_; } @property (nonatomic, readonly) id target; - (id)initWithTarget:(id)target selector:(SEL)selector queue:(id)queue; - (void)exec; @end @implementation PseudoTask @synthesize target=target_; - (id)initWithTarget:(id)target selector:(SEL)selector queue:(id)queue; { self = [super init]; if (self) { target_ = [target retain]; selector_ = selector; queue_ = [queue retain]; } return self; } - (void)exec { [target_ performSelector:selector_]; } - (void)dealloc { [target_ release]; [queue_ release]; } @end @interface PseudoSerialQueue : NSObject { NSCondition *condition_; NSMutableArray *array_; NSThread *thread_; } - (void)addTask:(id)target selector:(SEL)selector; @end @implementation PseudoSerialQueue - (id)init { self = [super init]; if (self) { array_ = [[NSMutableArray alloc] init]; condition_ = [[NSCondition alloc] init]; thread_ = [[NSThread alloc] initWithTarget:self selector:@selector(execQueue) object:nil]; [thread_ start]; } return self; } - (void)addTask:(id)target selector:(SEL)selector { [condition_ lock]; PseudoTask *task = [[PseudoTask alloc] initWithTarget:target selector:selector queue:self]; [array_ addObject:task]; [condition_ signal]; [condition_ unlock]; } - (void)quit { [self addTask:nil selector:nil]; } - (void)execQueue { for (;;) { NSAutoreleasePool *pool = [[NSAutoreleasePool alloc] init]; [condition_ lock]; while (array_.count == 0) [condition_ wait]; PseudoTask *task = [array_ objectAtIndex:0]; [array_ removeObjectAtIndex:0]; [condition_ unlock]; if (!task.target) { [pool drain]; break; } [task exec]; [task release]; [pool drain]; } } - (void)dealloc { [array_ release]; [condition_ release]; } @end 

如何使用:

 PseudoSerialQueue *q = [[[PseudoSerialQueue alloc] init] autorelease]; [q addTask:self selector:@selector(test0)]; [q addTask:self selector:@selector(test1)]; [q addTask:self selector:@selector(test2)]; [q quit]; 

你可以使用NSOperationQueue来模拟它,然后将任务计数设置为1。

编辑

– 哎呀,应该仔细阅读。 fifo解决scheme如下:

我想不出大多数ios开发者会在你的情况下使用的方式。

我不害怕编写线程程序,所以这里有一个解决scheme:

  • 创build一个fifo工作队列:
    • 支持locking
    • 拥有一个NSOperationQueue
    • 拥有一个NSOperation子类,旨在将工作人员从执行main工作的FIFO队列中拉出来。 一次只能有一个。
    • 拥有一个NSArray的工人将被运行(定义一个工人是由你决定的 – 这是一个NSInvocation,类,操作,…)

NSOperation子类将工作人员从FIFO工作队列中拉出,直到FIFO工作队列耗尽。

当fifo工作队列有worker且没有活动的子操作时,它创build一个子操作,并将其添加到操作队列中。

如果你不习惯编写线程程序,那么有一些缺陷 – 因为这个原因,这个解决scheme对于每个人来说都不是很理想,但是如果你已经习惯了使用所需的所有技术,那么这个解决scheme不需要很长的时间。

祝你好运

有一些NSOperationQueue文档编写者忘记提到的东西,使得这样的实现看起来微不足道,事实上并不是这样。

将最大并发操作数设置为1,只有当NSOperations从同一线程添加到队列时,才能保证串行。

我正在使用另一个选项,因为它只是工作。

从不同的线程添加NSOperations,但使用NSCondition来pipe理排队。 使用performSelectorOnBackgroundThread调用startOperations(并且应该,您不希望阻止locking主线程)…

startOperations方法表示由一个或多个NSOperation组成的单个作业。

 - (void)startOperations { NSAutoreleasePool *pool = [[NSAutoreleasePool alloc] init]; [[AppDelegate condition] lock]; while (![[[AppDelegate queue] operations] count] <= 0) { [[AppDelegate condition] wait]; } NSOperation *newOperation = [alloc, init]....; [[AppDelegate queue] addOperation:newOperation]; [[AppDelegate queue] waitUntilAllOperationsAreFinished]; // Don't forget this! NSOperation *newOperation1 = [alloc, init]....; [[AppDelegate queue] addOperation:newOperation1]; [[AppDelegate queue] waitUntilAllOperationsAreFinished]; // Don't forget this! NSOperation *newOperation2 = [alloc, init]....; [[AppDelegate queue] addOperation:newOperation2]; [[AppDelegate queue] waitUntilAllOperationsAreFinished]; // Don't forget this! // Add whatever number operations you need for this single job [[AppDelegate queue] signal]; [[AppDelegate queue] unlock]; [NotifyDelegate orWhatever] [pool drain]; } 

而已!

如果处理是在后台进行的,你真的需要严格按照规定吗? 如果你这样做了,你可以简单地通过设置你的依赖关系来达到同样的效果,所以1取决于0,2,1,3,2等。然后操作队列被强制按顺序处理它们。 设置最大并发操作数为1,队列也保证是串行的。