上一篇文章提到,利用NSThread可以實現多線程,但是線程的建立、維護和退出,都需要開發人員自己負責,當線程較多時,這將很難管理。NSOperation是一個抽象類別,封裝了一個task,你不能直接執行個體化它。你可以手動管理Operation,也可以將其加入到NSOperationQueue中,加入到NSOperationQueue中的Operation不需要開發人員去關注底層的多線程實現細節。
Cocoa提供了三種不同的NSOperation:
1. NSBlockOperation
Block Operations提供了利用Block 對象來執行task的方法。
2. NSInvocationOperation
顧名思義,Invocation Operation提供了調用普通method來執行task的方法。3. PlainOperation繼承自NSOperation,自訂NSOperation。在自訂NSOperation時,至少要重寫main和/或start函數。也必須重寫isExecuting 和isFinished,並通過KVO通知其他對象。你還必須為自訂的Operation指定一個初始化函數。2.1 NSBlockOperation先來一個Block Operation同步執行的代碼:
- (BOOL) application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions{NSBlockOperation *simpleOperation = [NSBlockOperation blockOperationWithBlock:^{ NSUInteger counter = 0;for (counter = 0; counter < 1000;counter++){NSLog(@"Count = %lu", (unsigned long)counter); } }];[simpleOperation start];NSLog(@"Main thread is here");return YES;}
通過NSLog輸出的順序可以看出,simpleOperation堵塞了mainthread,main thread會等待block執行完成之後再執行。
Operation預設是在建立它的線程中通過start方法來執行,我們可以將simpleOperation加入NSOperationQueue中來實現非同步執行,也可以自訂Operation並detach一個新的線程來執行:
NSOperationQueue *queue = [[NSOperationQueuealloc] init];
[queue addOperation:simpleOperation];
當你把一個Operation加入到queue之後,你不用手動的去start,因為queue會幫你完成,queue會管理所有加入到其中的Operation。如果你想自己控制(並不推薦這樣做),你可以採用detach thread的方法。如果有多個Operation需要添加,調用函數:
- (void)addOperations:(NSArray *)ops waitUntilFinished:(BOOL)wait
同時,可以擷取queue中當前有哪些Operation以及Operation的數目:
- (NSArray *)operations;
- (NSUInteger)operationCount;
你也可以為queue設定優先權:
- (NSOperationQueuePriority)queuePriority;
- (void)setQueuePriority:(NSOperationQueuePriority)p;
為queue添加一個便於記憶的名字:
- (void)setName:(NSString *)n ;
- (NSString *)name ;
暫停queue:
- (void)setSuspended:(BOOL)b;
- (BOOL)isSuspended;
2.2 NSInvocationOperation顧名思義,這種Operation就是在一個NSObject對象中去調用方法(method)。同樣的,我們先來看一下同步執行的情況:self.simpleOperation = [[NSInvocationOperation alloc]initWithTarget:self selector:@selector(simpleOperationEntry:) object:simpleObject];[self.simpleOperation start];
這樣,simpleOperation會在建立它的當前線程中(一般是main thread)執行,並且它的執行會堵塞當前線程。當然,這樣做並沒有多大的實際意義,但是如果我們把simpleOperation加入到queue中,它就可以和當前線程並存執行,從而提高效率。
NSNumber *firstNumber = [NSNumber numberWithInteger:111]; NSNumber *secondNumber = [NSNumber numberWithInteger:222];self.firstOperation =[[NSInvocationOperation alloc] initWithTarget:selfselector:@selector(firstOperationEntry:) object:firstNumber];//firstself.secondOperation = [[NSInvocationOperation alloc] initWithTarget:selfselector:@selector(secondOperationEntry:) object:secondNumber];//secondself.operationQueue = [[NSOperationQueue alloc] init];/* Add the operations to the queue */ [self.operationQueue addOperation:self.firstOperation];[self.operationQueue addOperation:self.secondOperation];
在上面的代碼裡,兩個Operation都在各自的線程中與main thread並存執行,而且這兩個Operation之間也是並行的。在queue中可以get、set最大並行Operation數:
- (NSInteger)maxConcurrentOperationCount;
- (void)setMaxConcurrentOperationCount:(NSInteger)cnt;
那麼,如果我要讓secondOperation在firstOperation之後執行呢?也就是說secondOperation需要等到firstOperation執行完成之後才開始。一個Operation可以依賴於另一個或者多個Operations,即等待依賴於的Operation執行完成之後再執行。如果你沒有為一個Operation添加依賴,那麼你對它何時執行將沒有控制權。addDependency:方法可以解決這一問題,在添加到queue之前為兩個Operation添加相依性屬性。
[self.secondOperation addDependency:self.firstOperation];
當不再需要依賴的時候,調用removeDependency:取消依賴。
[self.secondOperation removeDependency:self.firstOperation];
另外,NSInvocationOperation還可以以指定的初始化函數初始化:
- (id)initWithInvocation:(NSInvocation *)inv;// designated initializer
2.3 Operation其他需要注意的點一個Operation有相應的狀態來標識它的執行過程。
- (BOOL)isCancelled;
- (BOOL)isExecuting;
- (BOOL)isFinished;
- (BOOL)isConcurrent;
- (BOOL)isReady;
通過- (void)cancel可以取消一個Operation。
在queue中,通過- (void)cancelAllOperations來取消所有Operation。