iOS開發(fā)-NSOperation和NSOperationQueue的使用

NSOperation 是蘋果公司對 GCD 的封裝,完全面向對象纪铺,所以使用起來更好理解。
NSOperation 和 NSOperationQueue 分別對應 GCD 的 任務 和 隊列 。

操作步驟:
1.將要執(zhí)行的任務封裝到一個 NSOperation 對象中。
2.將此任務添加到一個 NSOperationQueue 對象中萌踱。
3.然后系統(tǒng)就會自動在執(zhí)行任務。

添加任務

NSOperation 只是一個抽象類限书,所以不能封裝任務虫蝶。
但它有 2 個子類用于封裝任務。NSInvocationOperation 和 NSBlockOperation 倦西。
創(chuàng)建一個 Operation 后能真,需要調用 start 方法來啟動任務,它會 默認在當前隊列同步執(zhí)行扰柠。當然你也可以在中途取消一個任務粉铐,只需要調用其 cancel 方法即可。

NSInvocationOperation

示例代碼:

-(void)test
{
    //1.創(chuàng)建NSInvocationOperation對象
    NSInvocationOperation *operation = [[NSInvocationOperation alloc] initWithTarget:self selector:@selector(run) object:nil];
    //2.開始執(zhí)行
    [operation start];

}

-(void)run
{
    NSLog(@"run at %@",[NSThread currentThread]);
}

運行結果:

[19275:3197092] run at <NSThread: 0x60400007cc80>{number = 1, name = main}

NSBlockOperation

示例代碼:

-(void)test
{
    //1.創(chuàng)建NSBlockOperation對象
    NSBlockOperation *operation = [NSBlockOperation blockOperationWithBlock:^{
        
        NSLog(@"%@", [NSThread currentThread]);
        
    }];
    
    //2.開始任務
    [operation start];
    
}

執(zhí)行結果:

[19319:3204356] <NSThread: 0x60400006fec0>{number = 1, name = main}

這樣的任務卤档,默認會在當前線程執(zhí)行蝙泼。但是 NSBlockOperation 還有一個方法:addExecutionBlock: ,通過這個方法可以給 Operation 添加多個執(zhí)行 Block劝枣。這樣 Operation 中的任務 會并發(fā)執(zhí)行汤踏,它會 在主線程和其它的多個線程 執(zhí)行這些任務。

-(void)test2
{
    //1.創(chuàng)建NSBlockOperation對象
    NSBlockOperation *operation = [NSBlockOperation blockOperationWithBlock:^{
        
        NSLog(@"%@", [NSThread currentThread]);
        
    }];
    
    //添加多個Block
    for (NSInteger i = 0; i < 5; i++) {
        
        [operation addExecutionBlock:^{
            
            NSLog(@"第%ld次:%@", i, [NSThread currentThread]);
            
        }];
        
    }
    
    //2.開始任務
    [operation start];
    //NOTE:addExecutionBlock 方法必須在 start() 方法之前執(zhí)行舔腾,否則就會報錯:

// -[NSBlockOperation addExecutionBlock:]: blocks cannot be added 
//after the operation has started executing or finished'
}

運行結果:

[19340:3206687] 第0次:<NSThread: 0x60000046d440>{number = 4, name = (null)}
[19340:3206689] <NSThread: 0x604000263740>{number = 3, name = (null)}
[19340:3206686] 第1次:<NSThread: 0x604000263780>{number = 5, name = (null)}
[19340:3206601] 第2次:<NSThread: 0x6000000725c0>{number = 1, name = main}
[19340:3206687] 第3次:<NSThread: 0x60000046d440>{number = 4, name = (null)}
[19340:3206689] 第4次:<NSThread: 0x604000263740>{number = 3, name = (null)}

自定義Operation

除了上面的兩種 Operation 以外溪胶,我們還可以自定義 Operation。自定義 Operation 需要繼承 NSOperation 類稳诚,并實現(xiàn)其 main() 方法哗脖,因為在調用 start() 方法的時候,內(nèi)部會調用 main() 方法完成相關邏輯。所以如果以上的兩個類無法滿足你的需求的時候才避,你就需要自定義了橱夭。你想要實現(xiàn)什么功能都可以寫在里面。除此之外桑逝,你還需要實現(xiàn) cancel() 在內(nèi)的各種方法棘劣。

NSOperationQueue

調用一個 NSOperation 對象的 start() 方法來啟動這個任務,但是這樣默認是 同步執(zhí)行 的肢娘。就算是 addExecutionBlock 方法呈础,也會在 當前線程和其他線程 中執(zhí)行,也就是說還是會占用當前線程橱健。這是就要用到隊列 NSOperationQueue 了而钞。
按類型來說的話一共有兩種類型:主隊列、其他隊列拘荡。
只要添加到隊列臼节,會自動調用任務的 start() 方法

主隊列

多線程方案都會有一個主線程(iOS中,像 pthread 這種多系統(tǒng)的方案并沒有珊皿,因為 UI線程 理論需要每種操作系統(tǒng)自己定制)瞭恰。這是一個特殊的線程袱巨,必須串行鸵隧。所以添加到主隊列的任務都會一個接一個地排著隊在主線程處理鹃两。

NSOperationQueue *queue = [NSOperationQueue mainQueue];

其他隊列

因為主隊列比較特殊,所以會單獨有一個類方法來獲得主隊列驶兜。那么通過初始化產(chǎn)生的隊列就是其他隊列了扼仲。
注意:其他隊列的任務會在其他線程并行執(zhí)行。

//1.創(chuàng)建一個其他隊列    
NSOperationQueue *queue = [[NSOperationQueue alloc] init];
//2.創(chuàng)建NSBlockOperation對象
NSBlockOperation *operation = [NSBlockOperation blockOperationWithBlock:^{
    NSLog(@"%@", [NSThread currentThread]);
}];
//3.添加多個Block
for (NSInteger i = 0; i < 5; i++)
 {
    [operation addExecutionBlock:^{
        NSLog(@"第%ld次:%@", i, [NSThread currentThread]);
    }];
}
//4.隊列添加任務
[queue addOperation:operation];

執(zhí)行結果:


[19376:3220751] 第1次:<NSThread: 0x604000263180>{number = 5, name = (null)}
[19376:3220745] 第0次:<NSThread: 0x604000262f00>{number = 4, name = (null)}
[19376:3220744] <NSThread: 0x600000468a80>{number = 3, name = (null)}
[19376:3220743] 第2次:<NSThread: 0x6040002631c0>{number = 6, name = (null)}
[19376:3220745] 第3次:<NSThread: 0x604000262f00>{number = 4, name = (null)}
[19376:3220751] 第4次:<NSThread: 0x604000263180>{number = 5, name = (null)}

將 NSOperationQueue 與 GCD的隊列 相比較就會發(fā)現(xiàn)抄淑,這里沒有并行隊列屠凶,那如果我想要10個任務在其他線程串行的執(zhí)行怎么辦?

不用管串行肆资、并行矗愧、同步、異步這些名詞郑原。NSOperationQueue 有一個參數(shù) maxConcurrentOperationCount 最大并發(fā)數(shù)唉韭,用來設置最多可以讓多少個任務同時執(zhí)行。當你把它設置為 1 的時候犯犁,就是串行纽哥。

NSOperationQueue 還有一個添加任務的方法,- (void)addOperationWithBlock:(void (^)(void))block;栖秕,這樣就可以添加一個任務到隊列中了,十分方便晓避。

NSOperation 有一個非常實用的功能簇捍,那就是添加依賴只壳。比如有 3 個任務:A: 從服務器上下載一張圖片,B:給這張圖片加個水印暑塑,C:把圖片返回給服務器吼句。這時就可以用到依賴了:


-(void)test7
{
    //1.任務一:下載圖片
    NSBlockOperation *operation1 = [NSBlockOperation blockOperationWithBlock:^{
        NSLog(@"下載圖片 - %@", [NSThread currentThread]);
        [NSThread sleepForTimeInterval:1.0];
    }];
    //2.任務二:打水印
    NSBlockOperation *operation2 = [NSBlockOperation blockOperationWithBlock:^{
        NSLog(@"打水印   - %@", [NSThread currentThread]);
        [NSThread sleepForTimeInterval:1.0];
    }];
    //3.任務三:上傳圖片
    NSBlockOperation *operation3 = [NSBlockOperation blockOperationWithBlock:^{
        NSLog(@"上傳圖片 - %@", [NSThread currentThread]);
        [NSThread sleepForTimeInterval:1.0];
    }];
    //4.設置依賴
    [operation2 addDependency:operation1];      //任務二依賴任務一
    [operation3 addDependency:operation2];      //任務三依賴任務二
    //5.創(chuàng)建隊列并加入任務
    NSOperationQueue *queue = [[NSOperationQueue alloc] init];
    [queue addOperations:@[operation3, operation2, operation1] waitUntilFinished:NO];
    
}

運行結果:

2017-11-13 16:57:38.558598+0800 NSOperationStudy[19735:3299963] 下載圖片 - <NSThread: 0x60400007b800>{number = 3, name = (null)}
2017-11-13 16:57:39.563069+0800 NSOperationStudy[19735:3299958] 打水印   - <NSThread: 0x60000027ef00>{number = 4, name = (null)}
2017-11-13 16:57:40.567363+0800 NSOperationStudy[19735:3299963] 上傳圖片 - <NSThread: 0x60400007b800>{number = 3, name = (null)}

注意:不能添加相互依賴,會死鎖事格,比如 A依賴B惕艳,B依賴A。
可以使用 removeDependency 來解除依賴關系驹愚。
可以在不同的隊列之間依賴远搪,依賴是添加到任務身上的,和隊列沒關系逢捺。

最后編輯于
?著作權歸作者所有,轉載或內(nèi)容合作請聯(lián)系作者
  • 序言:七十年代末谁鳍,一起剝皮案震驚了整個濱河市,隨后出現(xiàn)的幾起案子劫瞳,更是在濱河造成了極大的恐慌倘潜,老刑警劉巖,帶你破解...
    沈念sama閱讀 219,110評論 6 508
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件志于,死亡現(xiàn)場離奇詭異涮因,居然都是意外死亡,警方通過查閱死者的電腦和手機伺绽,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 93,443評論 3 395
  • 文/潘曉璐 我一進店門养泡,熙熙樓的掌柜王于貴愁眉苦臉地迎上來,“玉大人憔恳,你說我怎么就攤上這事瓤荔。” “怎么了钥组?”我有些...
    開封第一講書人閱讀 165,474評論 0 356
  • 文/不壞的土叔 我叫張陵输硝,是天一觀的道長。 經(jīng)常有香客問我程梦,道長点把,這世上最難降的妖魔是什么? 我笑而不...
    開封第一講書人閱讀 58,881評論 1 295
  • 正文 為了忘掉前任屿附,我火速辦了婚禮郎逃,結果婚禮上,老公的妹妹穿的比我還像新娘挺份。我一直安慰自己褒翰,他們只是感情好,可當我...
    茶點故事閱讀 67,902評論 6 392
  • 文/花漫 我一把揭開白布。 她就那樣靜靜地躺著优训,像睡著了一般朵你。 火紅的嫁衣襯著肌膚如雪。 梳的紋絲不亂的頭發(fā)上揣非,一...
    開封第一講書人閱讀 51,698評論 1 305
  • 那天抡医,我揣著相機與錄音,去河邊找鬼早敬。 笑死忌傻,一個胖子當著我的面吹牛,可吹牛的內(nèi)容都是我干的搞监。 我是一名探鬼主播水孩,決...
    沈念sama閱讀 40,418評論 3 419
  • 文/蒼蘭香墨 我猛地睜開眼,長吁一口氣:“原來是場噩夢啊……” “哼腺逛!你這毒婦竟也來了荷愕?” 一聲冷哼從身側響起,我...
    開封第一講書人閱讀 39,332評論 0 276
  • 序言:老撾萬榮一對情侶失蹤棍矛,失蹤者是張志新(化名)和其女友劉穎安疗,沒想到半個月后,有當?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體够委,經(jīng)...
    沈念sama閱讀 45,796評論 1 316
  • 正文 獨居荒郊野嶺守林人離奇死亡荐类,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點故事閱讀 37,968評論 3 337
  • 正文 我和宋清朗相戀三年,在試婚紗的時候發(fā)現(xiàn)自己被綠了茁帽。 大學時的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片玉罐。...
    茶點故事閱讀 40,110評論 1 351
  • 序言:一個原本活蹦亂跳的男人離奇死亡,死狀恐怖潘拨,靈堂內(nèi)的尸體忽然破棺而出吊输,到底是詐尸還是另有隱情,我是刑警寧澤铁追,帶...
    沈念sama閱讀 35,792評論 5 346
  • 正文 年R本政府宣布季蚂,位于F島的核電站,受9級特大地震影響琅束,放射性物質發(fā)生泄漏扭屁。R本人自食惡果不足惜,卻給世界環(huán)境...
    茶點故事閱讀 41,455評論 3 331
  • 文/蒙蒙 一涩禀、第九天 我趴在偏房一處隱蔽的房頂上張望料滥。 院中可真熱鬧,春花似錦艾船、人聲如沸葵腹。這莊子的主人今日做“春日...
    開封第一講書人閱讀 32,003評論 0 22
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽礁蔗。三九已至觉义,卻和暖如春,著一層夾襖步出監(jiān)牢的瞬間浴井,已是汗流浹背。 一陣腳步聲響...
    開封第一講書人閱讀 33,130評論 1 272
  • 我被黑心中介騙來泰國打工霉撵, 沒想到剛下飛機就差點兒被人妖公主榨干…… 1. 我叫王不留磺浙,地道東北人。 一個月前我還...
    沈念sama閱讀 48,348評論 3 373
  • 正文 我出身青樓徒坡,卻偏偏與公主長得像撕氧,于是被迫代替她去往敵國和親。 傳聞我的和親對象是個殘疾皇子喇完,可洞房花燭夜當晚...
    茶點故事閱讀 45,047評論 2 355

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