完全瞭解NSOperation的自定義

閱讀完筆記-iOS 多線程:『NSOperation、NSOperationQueue』詳盡總結以後,或許對於如何自定義NSOperation還有疑惑,那麼下面內容,能夠幫助你解決這個問題。若是對於NSOperation的相關基礎知識,還有疑問的,那麼,你能夠點擊上面那篇文章,能夠幫助你解惑。數組

NSOperation 與 NSOperationQueue 解析

爲何要使用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子類有兩種方式,併發和非併發。 非併發只須要繼承NSOperation後,實現main方法便可。而併發的操做相對較多一點,下面將詳細描述。atom

非併發的NSOperation子類

官方文檔描述:
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子類,實在想不出有什麼場景須要來用它,畢竟不方便。

併發的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];
}
複製代碼

關於NSOperationNSOperationQueue的自定義子類的使用基本上描述完了,一些比較細節的東西,能夠參考官方文檔。

有關NSOperationNSOperationQueue的應用,咱們能夠閱讀有關AFNetworkingSDWebImage的源碼,源碼中使用了大量的NSOperation操做。

相關文章
相關標籤/搜索