淺讀NSOperationQueue&NSOperation

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í)行响蓉。


operationQueue.png

不過這里有個小問題硕勿,為什么線程都是從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];
?著作權歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
  • 序言:七十年代末妈拌,一起剝皮案震驚了整個濱河市,隨后出現(xiàn)的幾起案子蓬蝶,更是在濱河造成了極大的恐慌尘分,老刑警劉巖,帶你破解...
    沈念sama閱讀 222,252評論 6 516
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件丸氛,死亡現(xiàn)場離奇詭異培愁,居然都是意外死亡,警方通過查閱死者的電腦和手機缓窜,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 94,886評論 3 399
  • 文/潘曉璐 我一進店門定续,熙熙樓的掌柜王于貴愁眉苦臉地迎上來,“玉大人禾锤,你說我怎么就攤上這事私股。” “怎么了恩掷?”我有些...
    開封第一講書人閱讀 168,814評論 0 361
  • 文/不壞的土叔 我叫張陵倡鲸,是天一觀的道長。 經(jīng)常有香客問我黄娘,道長峭状,這世上最難降的妖魔是什么克滴? 我笑而不...
    開封第一講書人閱讀 59,869評論 1 299
  • 正文 為了忘掉前任,我火速辦了婚禮宁炫,結(jié)果婚禮上偿曙,老公的妹妹穿的比我還像新娘。我一直安慰自己羔巢,他們只是感情好望忆,可當我...
    茶點故事閱讀 68,888評論 6 398
  • 文/花漫 我一把揭開白布。 她就那樣靜靜地躺著竿秆,像睡著了一般启摄。 火紅的嫁衣襯著肌膚如雪。 梳的紋絲不亂的頭發(fā)上幽钢,一...
    開封第一講書人閱讀 52,475評論 1 312
  • 那天歉备,我揣著相機與錄音,去河邊找鬼匪燕。 笑死蕾羊,一個胖子當著我的面吹牛,可吹牛的內(nèi)容都是我干的帽驯。 我是一名探鬼主播龟再,決...
    沈念sama閱讀 41,010評論 3 422
  • 文/蒼蘭香墨 我猛地睜開眼,長吁一口氣:“原來是場噩夢啊……” “哼尼变!你這毒婦竟也來了利凑?” 一聲冷哼從身側(cè)響起,我...
    開封第一講書人閱讀 39,924評論 0 277
  • 序言:老撾萬榮一對情侶失蹤嫌术,失蹤者是張志新(化名)和其女友劉穎哀澈,沒想到半個月后,有當?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體度气,經(jīng)...
    沈念sama閱讀 46,469評論 1 319
  • 正文 獨居荒郊野嶺守林人離奇死亡割按,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點故事閱讀 38,552評論 3 342
  • 正文 我和宋清朗相戀三年,在試婚紗的時候發(fā)現(xiàn)自己被綠了磷籍。 大學時的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片哲虾。...
    茶點故事閱讀 40,680評論 1 353
  • 序言:一個原本活蹦亂跳的男人離奇死亡,死狀恐怖择示,靈堂內(nèi)的尸體忽然破棺而出束凑,到底是詐尸還是另有隱情,我是刑警寧澤栅盲,帶...
    沈念sama閱讀 36,362評論 5 351
  • 正文 年R本政府宣布汪诉,位于F島的核電站,受9級特大地震影響,放射性物質(zhì)發(fā)生泄漏扒寄。R本人自食惡果不足惜鱼鼓,卻給世界環(huán)境...
    茶點故事閱讀 42,037評論 3 335
  • 文/蒙蒙 一、第九天 我趴在偏房一處隱蔽的房頂上張望该编。 院中可真熱鬧迄本,春花似錦、人聲如沸课竣。這莊子的主人今日做“春日...
    開封第一講書人閱讀 32,519評論 0 25
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽于樟。三九已至公条,卻和暖如春,著一層夾襖步出監(jiān)牢的瞬間迂曲,已是汗流浹背靶橱。 一陣腳步聲響...
    開封第一講書人閱讀 33,621評論 1 274
  • 我被黑心中介騙來泰國打工, 沒想到剛下飛機就差點兒被人妖公主榨干…… 1. 我叫王不留路捧,地道東北人关霸。 一個月前我還...
    沈念sama閱讀 49,099評論 3 378
  • 正文 我出身青樓,卻偏偏與公主長得像杰扫,于是被迫代替她去往敵國和親队寇。 傳聞我的和親對象是個殘疾皇子,可洞房花燭夜當晚...
    茶點故事閱讀 45,691評論 2 361

推薦閱讀更多精彩內(nèi)容

  • 本文首發(fā)于我的個人博客:「程序員充電站」[https://itcharge.cn]文章鏈接:「傳送門」[https...
    ITCharge閱讀 110,204評論 135 749
  • 概述 這篇文章中炭序,我不會說多線程是什么啤覆、線程和進程的區(qū)別、多線程有什么用惭聂,當然我也不會說什么是串行窗声、什么是并行等問...
    hashakey閱讀 305評論 0 0
  • 一、簡介 除了辜纲,NSThread和GCD實現(xiàn)多線程笨觅,配合使用NSOperation和NSOperationQueu...
    怎樣m閱讀 985評論 0 5
  • 目錄 一、基本概念1.多線程2.串行和并行耕腾, 并發(fā)3.隊列與任務4.同步與異步5.線程狀態(tài)6.多線程方案 二见剩、GC...
    BohrIsLay閱讀 1,588評論 5 12
  • 應憐碧波待人開 畫眉啼窗久難猜 湖畔青柳吹又續(xù) 翹首向東為誰發(fā)
    如丹閱讀 92評論 0 0