閱讀完筆記-iOS 多線程:『NSOperation、NSOperationQueue』詳盡總結以後,或許對於如何自定義NSOperation
還有疑惑,那麼下面內容,能夠幫助你解決這個問題。若是對於NSOperation
的相關基礎知識,還有疑問的,那麼,你能夠點擊上面那篇文章,能夠幫助你解惑。數組
爲何要使用NSOperation
?
NSOperation
提供任務的封裝,NSOperationQueue
顧名思義,提供執行隊列,能夠自動實現多核並行計算,自動管理線程的生命週期,若是是併發的狀況,其底層也使用線程池模型來管理,基本上能夠說這兩個類提供的功能覆蓋了GCD
,而且提供了更多可定製的開發方式,開發者能夠按需選擇。
NSOperation
把封裝好的任務交給不一樣的NSOperationQueue
便可進行串行或併發隊列的執行。
一般狀況下,任務會交給NSOperation
類的一個方法,main
或者start
方法,因此咱們要自定義繼承NSOperation
類的話,須要重寫相關方法。bash
NSOperation
經常使用屬性和方法重寫的方法多線程
// 對於併發的Operation須要重寫改方法
- (void)start;
// 非併發的Operation須要重寫該方法
- (void)main;
複製代碼
相關屬性併發
// 任務是否取消(只讀) 自定義子類,需重寫該屬性
@property (readonly, getter=isCancelled) BOOL cancelled;
// 可取消操做,實質是標記 isCancelled 狀態,自定義子類,需利用該方法標記取消狀態
- (void)cancel;
// 任務是否正在執行(只讀),自定義子類,需重寫該屬性
@property (readonly, getter=isExecuting) BOOL executing;
// 任務是否結束(只讀),自定義子類,需重寫該屬性
// 若是爲YES,則隊列會將任務移除隊列
@property (readonly, getter=isFinished) BOOL finished;
// 判斷任務是否爲併發(只讀),默認返回NO
// 自定義子類,需重寫getter方法,並返回YES
@property (readonly, getter=isAsynchronous) BOOL asynchronous;
// 任務是否準備就緒(只讀)
// 對於加入隊列的任務來講,ready爲YES,則表示該任務即將開始執行
// 若是存在依賴關係的任務沒有執行完,則ready爲NO
@property (readonly, getter=isReady) BOOL ready;
複製代碼
操做同步async
// 添加任務依賴
- (void)addDependency:(NSOperation *)op;
// 刪除任務依賴
- (void)removeDependency:(NSOperation *)op;
typedef NS_ENUM(NSInteger, NSOperationQueuePriority) {
NSOperationQueuePriorityVeryLow = -8L,
NSOperationQueuePriorityLow = -4L,
NSOperationQueuePriorityNormal = 0,
NSOperationQueuePriorityHigh = 4,
NSOperationQueuePriorityVeryHigh = 8
};
// 任務在隊列裏的優先級
@property NSOperationQueuePriority queuePriority;
// 會在當前操做執行完畢時調用completionBlock
@property (nullable, copy) void (^completionBlock)(void);
// 阻塞當前線程,直到該操做結束,可用於線程執行順序的同步
- (void)waitUntilFinished;
複製代碼
NSOperationQueue
經常使用屬性和方法添加任務ide
// 向隊列中添加一個任務
- (void)addOperation:(NSOperation *)op;
// 向隊列中添加操做數組,wait 標誌是否阻塞當前線程直到全部操做結束
- (void)addOperations:(NSArray<NSOperation *> *)ops waitUntilFinished:(BOOL)wait;
// 向隊列中添加一個 block 類型操做對象。
- (void)addOperationWithBlock:(void (^)(void))block;
複製代碼
相關屬性ui
// 獲取隊列中全部任務(只讀)
@property (readonly, copy) NSArray<__kindof NSOperation *> *operations;
// 獲取隊列中任務數量(只讀)
@property (readonly) NSUInteger operationCount;
// 隊列支持的最大任務併發數
@property NSInteger maxConcurrentOperationCount;
// 隊列是否掛起
@property (getter=isSuspended) BOOL suspended;
// 隊列名字
@property (nullable, copy) NSString *name
複製代碼
相關方法this
// 取消隊列中全部的任務
- (void)cancelAllOperations;
// 阻塞當前線程,直到全部任務完成
- (void)waitUntilAllOperationsAreFinished;
// 類屬性,獲取當前隊列
@property (class, readonly, strong, nullable) NSOperationQueue *currentQueue;
// 類屬性,獲取主隊列(併發數爲1)
@property (class, readonly, strong) NSOperationQueue *mainQueue;
複製代碼
在官方文檔中支出,自定義NSOperation
子類有兩種方式,併發和非併發。 非併發只須要繼承NSOperation
後,實現main
方法便可。而併發的操做相對較多一點,下面將詳細描述。atom
官方文檔描述:
Methods to Override
For non-concurrent operations, you typically override only one method: main
Into this method, you place the code needed to perform the given task.spa
在官方文檔中指出,非併發任務,直接將須要執行的任務放在main
方法中,而後直接調用便可。 這樣直接調用main
方法會存在一個問題,因爲沒有實現finished
屬性,因此獲取finished
屬性時,只會返回NO,並且任務加入到隊列後,不會被刪除,另外任務執行完後,回調也不會被執行,因此最好不要只實現一個main
方法來使用。 並且,其實也沒有必要使用這種非併發的NSOperation
子類,實在想不出有什麼場景須要來用它,畢竟不方便。
官方文檔描述:
Methods to Override
If you are creating a concurrent operation, you need to override the following methods and properties at a minimum:
start
asynchronous
executing
finished
經過官方文檔能夠知道,實現併發的自定義子類,須要重寫下面幾個方法或屬性:
start
:把須要執行的任務放在start
方法裏,任務加到隊列後,隊列會管理任務並在線程被調度後,調用start
方法,不須要調用父類的方法asynchronous
:表示是否併發執行executing
:表示任務是否正在執行,須要手動調用KVO方法來進行通知,方便其餘類監聽了任務的該屬性finished
:表示任務是否結束,須要手動調用KVO方法來進行通知,隊列也須要監聽改屬性的值,用於判斷任務是否結束相關代碼:
@interface ZBOperation : NSOperation
@property (nonatomic, readwrite, getter=isExecuting) BOOL executing;
@property (nonatomic, readwrite, getter=isFinished) BOOL finished;
@end
@implementation ZBOperation
// 由於父類的屬性是Readonly的,重載時若是須要setter的話則須要手動合成。
@synthesize executing = _executing;
@synthesize finished = _finished;
- (void)start {
@autoreleasepool{
self.executing = YES;
if (self.cancelled) {
[self done];
return;
}
// 任務。。。
}
// 任務執行完成,手動設置狀態
[self done];
}
- (void)done {
self.finished = YES;
self.executing = NO;
}
#pragma mark - setter -- getter
- (void)setExecuting:(BOOL)executing {
//調用KVO通知
[self willChangeValueForKey:@"isExecuting"];
_executing = executing;
//調用KVO通知
[self didChangeValueForKey:@"isExecuting"];
}
- (BOOL)isExecuting {
return _executing;
}
- (void)setFinished:(BOOL)finished {
if (_finished != finished) {
[self willChangeValueForKey:@"isFinished"];
_finished = finished;
[self didChangeValueForKey:@"isFinished"];
}
}
- (BOOL)isFinished {
return _finished;
}
// 返回YES 標識爲併發Operation
- (BOOL)isAsynchronous {
return YES;
}
// 調用類
- (void)congfigOperation {
self.queue = [[NSOperationQueue alloc] init];
[self.queue setMaxConcurrentOperationCount:2];
self.zbOperation = [[ZBOperation alloc] init];
[self.queue addOperation:self.zbOperation];
}
複製代碼
關於NSOperation
和NSOperationQueue
的自定義子類的使用基本上描述完了,一些比較細節的東西,能夠參考官方文檔。
有關NSOperation
和NSOperationQueue
的應用,咱們能夠閱讀有關AFNetworking
和SDWebImage
的源碼,源碼中使用了大量的NSOperation
操做。