NSOperationQueue
??NSOperationQueue是管理一組操作(operation)的隊列宰闰。隊列中操作是根據(jù)操作的優(yōu)先級(queuePriority)和操作的依賴關系(Dependency)來決定執(zhí)行的先后順序久锥。操作一旦加入到隊列中档冬,該操作會一直存在這個隊列中,不能直接從隊列中刪除嵌纲,除非改操作被顯示的取消( 調(diào)用cancel() )或者完成才能移除。
??注意:取消操作會導致操作忽略它可能擁有的任何依賴關系,例如:operationA依賴operationB准谚,并且operationB還沒執(zhí)行,此時你想取消operationA,這個時候operationA不會等operationB完成后在執(zhí)行取消操作去扣,而是直接執(zhí)行start方法將operationA標記為完成狀態(tài)柱衔,然后從隊列中刪除。
??隊列通常會提供運行操作的線程愉棱,使用libdispatch庫(中央調(diào)度)啟動它們的操作唆铐。操作不管是異步或者同步,都是在單獨的線程上執(zhí)行奔滑,所以可以安全的使用多個線程中的單個NSOperationQueue對象艾岂,不需要創(chuàng)建額外的鎖來同步該對象的訪問。
讓我們看看NSOperationQueue的屬性和方法:
//操作數(shù)組朋其,只讀
@property (readonly, copy) NSArray<__kindof NSOperation *> *operations;
//包含操作的數(shù)量王浴,只讀
@property (readonly) NSUInteger operationCount ;
//隊列中同時可執(zhí)行的最大操作數(shù)量
@property NSInteger maxConcurrentOperationCount;
//是否暫停執(zhí)行操作
@property (getter=isSuspended) BOOL suspended;
// 隊列的名字
@property (nullable, copy) NSString *name ;
//系統(tǒng)管理的隊列的資源分配
@property NSQualityOfService qualityOfService;
//依賴的現(xiàn)有隊列梅猿,默認為nil
@property (nullable, assign /* actually retain */) dispatch_queue_t underlyingQueue;
//當前的操作隊列
@property (class, readonly, strong, nullable) NSOperationQueue *currentQueue
//當前主線程關聯(lián)的隊列
@property (class, readonly, strong) NSOperationQueue *mainQueue
//添加操作對象
- (void)addOperation:(NSOperation *)op;
//添加操作對象組 waitUntilFinished:是否阻塞當前線程氓辣,等所有操作都完成
- (void)addOperations:(NSArray<NSOperation *> *)ops waitUntilFinished:(BOOL)wait;
//添加操作任務
- (void)addOperationWithBlock:(void (^)(void))block袱蚓;
//取消所有的操作
- (void)cancelAllOperations;
//阻塞線程知道所有操作完成
- (void)waitUntilAllOperationsAreFinished;
代碼實現(xiàn)一下:
NSOperationQueue *queue = [[NSOperationQueue alloc] init];
queue.name = @"OperationQueueTest";
NSLog(@"%@",queue.name);
queue.maxConcurrentOperationCount = 2;
NSOperation *operationA = [NSBlockOperation blockOperationWithBlock:^{
NSLog(@"operationA:%@", [NSThread currentThread]);
//為了檢驗maxConcurrentOperationCount屬性
sleep(5);
}];
NSOperation *operationB = [NSBlockOperation blockOperationWithBlock:^{
NSLog(@"operationB:%@", [NSThread currentThread]);
sleep(5);
}];
NSOperation *operationC = [NSBlockOperation blockOperationWithBlock:^{
NSLog(@"operationC:%@", [NSThread currentThread]);
}];
NSOperation *operationD = [NSBlockOperation blockOperationWithBlock:^{
NSLog(@"operationD:%@", [NSThread currentThread]);
}];
NSOperation *operationE = [NSBlockOperation blockOperationWithBlock:^{
NSLog(@"operationE:%@", [NSThread currentThread]);
}];
//operationD依賴于A钞啸,B,C喇潘,所以必須等ABC完成后才能執(zhí)行D
[operationD addDependency:operationA];
[operationD addDependency:operationB];
[operationD addDependency:operationC];
[queue addOperation:operationA];
[queue addOperation:operationB];
[queue addOperation:operationC];
[queue addOperation:operationD];
[queue addOperation:operationE];
從下面的輸出可以看到爽撒,運行后可以看到線程的最大并發(fā)數(shù)為2,D在ABC完成后才執(zhí)行响蓉。
不過這里有個小問題硕勿,為什么線程都是從number = 3開始的,搜了一些資料枫甲,也嘗試了一下源武,只知道number = 1 為主線程,那么number = 2 是什么想幻?如果有讀者知道希望告訴我一下粱栖,不勝感激!
NSOperation
??NSOperation是表示與單個任務關聯(lián)的代碼和數(shù)據(jù)的抽象類脏毯,所以不能直接使用闹究,需要使用系統(tǒng)定義的子類(NSInvocationOperation和NSBlockOperation)來執(zhí)行實際的任務。雖然NSOperation是抽象的食店,但是它的基本實現(xiàn)包含了重要的邏輯來協(xié)調(diào)任務的安全執(zhí)行渣淤。
??如果你不想使用NSOperationQueue赏寇,可以直接調(diào)用NSOperation的start() 方法來執(zhí)行操作,只能二選一价认。手動執(zhí)行操作會增加代碼的負擔嗅定,因為啟動不處于就緒狀態(tài)的操作會觸發(fā)異常。
//開始操作
- (void)start;
//操作任務的入口用踩,一般用于自定義的NSOperation的子類
- (void)main;
//操作是否取消渠退,默認為NO
@property (readonly, getter=isCancelled) BOOL cancelled;
//取消操作
- (void)cancel;
//操作是否執(zhí)行
@property (readonly, getter=isExecuting) BOOL executing;
//操作是否完成
@property (readonly, getter=isFinished) BOOL finished;
//操作是否異步執(zhí)行其他任務
@property (readonly, getter=isConcurrent) BOOL concurrent;
//操作是否異步執(zhí)行任務
@property (readonly, getter=isAsynchronous) BOOL asynchronous API_AVAILABLE(macos(10.8), ios(7.0), watchos(2.0), tvos(9.0));
//操作是否準備被執(zhí)行
@property (readonly, getter=isReady) BOOL ready;
//添加依賴
- (void)addDependency:(NSOperation *)op;
//移除依賴
- (void)removeDependency:(NSOperation *)op;
//操作依賴的的操作組
@property (readonly, copy) NSArray<NSOperation *> *dependencies;
//操作在隊列的優(yōu)先級
@property NSOperationQueuePriority queuePriority;
//操作的主要任務發(fā)出后的回調(diào)
@property (nullable, copy) void (^completionBlock)(void) API_AVAILABLE(macos(10.6), ios(4.0), watchos(2.0), tvos(9.0));
//操作完成前是否阻塞當前線程的執(zhí)行
- (void)waitUntilFinished API_AVAILABLE(macos(10.6), ios(4.0), watchos(2.0), tvos(9.0));
//操作的線程優(yōu)先級(棄用)
@property double threadPriority API_DEPRECATED("Not supported", macos(10.6,10.10), ios(4.0,8.0), watchos(2.0,2.0), tvos(9.0,9.0));
//系統(tǒng)資源的分配
@property NSQualityOfService qualityOfService API_AVAILABLE(macos(10.10), ios(8.0), watchos(2.0), tvos(9.0));
//操作名字
@property (nullable, copy) NSString *name API_AVAILABLE(macos(10.10), ios(8.0), watchos(2.0), tvos(9.0));
NSBlockOperation
??NSBlockOperation是NSOperation的子類,用來管理一個或者多個block的并發(fā)執(zhí)行的操作脐彩。一個blockOperation可以執(zhí)行一個或多個block碎乃,當執(zhí)行多個block的時候,要等所有block都執(zhí)行完成后惠奸,才考慮operation本身荠锭。
//創(chuàng)建一個帶有block的opertation對象。
+ (instancetype)blockOperationWithBlock:(void (^)(void))block;
//添加執(zhí)行的block
- (void)addExecutionBlock:(void (^)(void))block;
//opertaion中含有的所有執(zhí)行block
@property (readonly, copy) NSArray<void (^)(void)> *executionBlocks;
// 創(chuàng)建
NSBlockOperation *operation = [[NSBlockOperation alloc] init];
NSBlockOperation *operation1 = [NSBlockOperation blockOperationWithBlock:^{}];
// 操作完成的時候回調(diào)
[operationA setCompletionBlock:^{}];
// 添加任務
[operation addExecutionBlock:^{}];
// 開始 異步并發(fā):第一個任務在當前線程晨川,其他任務在其他線程
[operation start];
// 添加到隊列 所有任務都在同一個隊列中
[queue addOperation:operation1];
// 設置依賴 A->B->C
[operationB addDependency:operationA];
[operationC addDependency:operationB];
NSInvocationOperation
??NSInvocationOperation是NSOperation的子類,管理那些指定為調(diào)用的封裝好的單個任務的執(zhí)行删豺。用來發(fā)起一個操作共虑,這個操作能調(diào)用指定對象上的方法。
//創(chuàng)建一個調(diào)用特定對象的方法的invocationOperation
- (nullable instancetype)initWithTarget:(id)target selector:(SEL)sel object:(nullable id)arg;
//根據(jù)一個NSInvocation對象 創(chuàng)建一個InvocationOpetation
- (instancetype)initWithInvocation:(NSInvocation *)inv NS_DESIGNATED_INITIALIZER;
// 包含的invocation對象
@property (readonly, retain) NSInvocation *invocation;
//調(diào)用方法或者invocation的結(jié)果
@property (nullable, readonly, retain) id result;
// 創(chuàng)建
NSInvocationOperation *operation = [[NSInvocationOperation alloc] initWithTarget:self selector:@selector(download) object:nil];
// 開始 同步執(zhí)行(在當前線程執(zhí)行操作)
[operation start];
// 添加操作到隊列中呀页,會自動異步執(zhí)行
[queue addOperation:operation];