Apple的Grand Central Dispatch(GCD)非常棒,但仅适用于iOS 4.0或更高版本。 Apple的documentation说,“[A]序列化操作队列不提供与Grand Central Dispatch中的串行调度队列完全相同的行为”(因为队列不是FIFO,但顺序由依赖关系和优先级决定)
在GCD发布之前支持操作系统版本的同时,实现与GCD的串行调度队列相同效果的正确方法是什么?或者换句话说,在想要支持低于4.0的版本的iOS应用程序中处理简单后台处理(执行Web服务请求等)的推荐方法是什么?
答案 0 :(得分:4)
这个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];
答案 1 :(得分:3)
您可以使用NSOperationQueue
进行模拟,然后将任务计数设置为1。
修改强>
- 哎呀,应该仔细阅读。 fifo解决方案如下:
我想不出大多数ios开发者会在你的情况下使用的方式。
我不怕编写线程程序,所以这里有一个解决方案:
main
的实现中从fifo队列中提取工作者。一次只能存在一个。NSOperation子类将工作人员从fifo工作队列中拉出,直到fifo工作队列耗尽。
当fifo工作队列有worker并且没有活动子操作时,它会创建一个子操作,并将其添加到其操作队列。
如果你不习惯编写线程程序会有一些陷阱 - 因此,这个解决方案并不适合所有人,但如果你已经习惯使用所有技术,这个解决方案不会花很长时间必需的。 祝你好运答案 2 :(得分:3)
似乎人们要为重写NSRunloop付出很多努力。根据{{3}}:
您的应用无法创建 或明确管理NSRunLoop 对象。每个NSThread对象, 包括应用程序的主要内容 thread,有一个NSRunLoop对象 自动为它创建 需要的。
创建一个可用的队列肯定是微不足道的答案:
- (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];
Cocoa定义了一个自定义输入源 允许您执行选择器 在任何线程上。 ...执行选择器请求 在目标线程上序列化, 缓解许多人 可能的同步问题 在运行多个方法时发生 在一个线程上。
所以你有一个明确的串行队列。当然,我的写作并不是很精彩,因为我已经告诉run循环永远运行了,你可能更喜欢稍后终止,但这些都很容易修改。
答案 3 :(得分:2)
有些事情NSOperationQueue文档作者忘了提及,这样的实现似乎微不足道,实际上并非如此。
将最大并发操作数设置为1可保证仅为串行 如果NSOperations从同一个线程添加到队列中。
我正在使用其他选项,因为它只是有效。
从不同的线程添加NSOperations,但使用NSCondition来管理排队。 使用performSelectorOnBackgroundThread调用startOperations(并且你不应该用锁来阻止主线程)...
startOperations方法表示由一个或多个NSOperations组成的单个作业。
- (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];
}
就是这样!
答案 4 :(得分:0)
如果处理在后台,你真的需要严格按顺序进行处理吗?如果这样做,只需设置依赖关系就可以达到同样的效果,因此1取决于0,2 on 1,3 on on 2等等。然后强制操作队列按顺序处理它们。将最大并发操作数设置为1,并且队列也保证是串行的。