![](/img/trans.png)
[英]Block in serial dispatch queue not executing - GCD iOS Objective-C
[英]Equivalent of GCD serial dispatch queue in iOS 3.x
Apple 的 Grand Central Dispatch (GCD) 很棒,但僅適用於 iOS 4.0 或更高版本。 Apple 的文檔說,“[A] 序列化操作隊列不提供與 Grand Central Dispatch 中的串行調度隊列完全相同的行為”(因為隊列不是 FIFO,但順序由依賴關系和優先級決定)。
在支持 GCD 發布之前的 OS 版本的同時,實現與 GCD 的串行調度隊列相同的效果的正確方法是什么? 或者換一種說法,在想要支持低於 4.0 版本的 iOS 應用程序中處理簡單后台處理(執行 web 服務請求等)的推薦方法是什么?
這個 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 解決方案如下:
我想不出大多數 ios 開發人員會在您的情況下使用的方法。
我不怕編寫線程程序,所以這是一種解決方案:
main
的實現中從 fifo 隊列中拉出工人。 一次只能存在一個。NSOperation 子類從 fifo 工作隊列中拉出工作人員,直到 fifo 工作隊列用完。
當 fifo 工作隊列有工人並且沒有活動的子操作時,它會創建一個子操作,並將其添加到其操作隊列中。
如果您不習慣編寫線程程序,則會有一些陷阱——因此,這個解決方案並不適合所有人,但如果您已經習慣使用所有所需的技術,那么編寫這個解決方案不會花費很長時間。
祝你好運
似乎人們會付出很多努力來重寫 NSRunloop。 根據NSRunloop 文檔:
您的應用程序不能創建或顯式管理 NSRunLoop 對象。 每個 NSThread object,包括應用程序的主線程,都有一個根據需要自動為其創建的 NSRunLoop object。
因此,毫無疑問,簡單的答案是創建一個可用的隊列:
- (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 定義了一個自定義輸入源,允許您在任何線程上執行選擇器。 ...執行選擇器請求在目標線程上進行序列化,從而減輕了在一個線程上運行多個方法時可能出現的許多同步問題。
所以你有一個明確的串行隊列。 當然,我的寫得並不出色,因為我已經告訴運行循環永遠運行,你可能更喜歡一個你可以稍后終止的,但這些很容易修改。
有些事情 NSOperationQueue 文檔作者忘記提及,使得這樣的實現看起來微不足道,而實際上並非如此。
僅當從同一線程將 NSOperations 添加到隊列中時,才能保證將最大並發操作計數設置為 1 是串行的。
我正在使用另一個選項,因為它可以正常工作。
從不同的線程添加 NSOperations 但使用 NSCondition 來管理隊列。 startOperations 可以(並且應該,你不想用鎖阻塞主線程)用 performSelectorOnBackgroundThread 調用...
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];
}
而已!
如果無論如何處理都在后台,你真的需要它嚴格有序嗎? 如果你這樣做了,你可以簡單地通過設置你的依賴來達到同樣的效果,所以 1 依賴於 0、2 依賴於 1、3 依賴於 2 等等。然后強制操作隊列按順序處理它們。 設置最大並發操作數為1,隊列也保證是串行的。
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.