一眠砾、NSOperation介紹:基本語法
NSOperation在iOS4后也基于GCD實(shí)現(xiàn),但是相對(duì)于GCD來說可控性更強(qiáng)托酸,并且可以加入操作依賴褒颈。NSOperation是一個(gè)抽象類,系統(tǒng)為我們提供了NSBlockOperation和NSInvocationOperation兩個(gè)子類励堡,并且可以創(chuàng)建繼承自NSOperation的自定義類谷丸。相比于GCD,NSOperation類更加面向?qū)ο笥幔_發(fā)者除了不需要去了解線程相關(guān)的概念之外刨疼,甚至連GCD中需要了解的異步/同步、并行/串行都不太需要深入了解摊趾,開發(fā)者只要懂得任務(wù)和隊(duì)列即可币狠。
1、NSOperation的子類
由于NSOperation是一個(gè)抽象類砾层,因此不能夠直接使用NSOperation漩绵,但蘋果提供了兩個(gè)NSOperation的子類,NSBlockOperation和NSInvocationOperation肛炮,除此之外止吐,我們還可以自定義NSOperation的子類。
二侨糟、NSOperation介紹:線程間通信
在NSOperationQueue類中碍扔,也可以獲取主線程隊(duì)列,相關(guān)更新UI的任務(wù)必須放在主隊(duì)列中完成秕重。
下方示例中不同,當(dāng)點(diǎn)擊開始下載按鈕后,會(huì)創(chuàng)建一個(gè)NSBlockOperation對(duì)象溶耘,放在一個(gè)普通隊(duì)列中執(zhí)行二拐,開始下載網(wǎng)絡(luò)圖片。此時(shí)凳兵,由于下載任務(wù)是在非主線程中進(jìn)行的百新,所以界面上的switch按鈕是可以點(diǎn)擊的。等下載完成后庐扫,需要在下載任務(wù)中返回主線程去設(shè)置UI界面饭望。
- (IBAction)startBtnAction:(id)sender {
NSBlockOperation *downloadTask = [NSBlockOperation blockOperationWithBlock:^{
//下載網(wǎng)絡(luò)圖片
NSString *urlString = @"https://encrypted-tbn0.gstatic.com/images?q=tbn:ANd9GcRc3Rs3zHlmPEdusO8G_I1xHyKsYUujL9ZX76nfgkVVu69oU_gosw";
NSURL *url = [NSURL URLWithString:urlString];
NSData *imageData = [NSData dataWithContentsOfURL:url];
UIImage *image = [UIImage imageWithData:imageData];
//返回主線程設(shè)置ui
NSOperationQueue *mainQueue = [NSOperationQueue mainQueue];
[mainQueue addOperationWithBlock:^{
self.imageView.image = image;
}];
}];
//創(chuàng)建queue
NSOperationQueue *queue = [[NSOperationQueue alloc] init];
[queue addOperation:downloadTask];
}
三仗哨、NSOperation介紹:任務(wù)間的執(zhí)行依賴
NSOperation中提供了更加方便直觀的方式來設(shè)置任務(wù)執(zhí)行的先后順序關(guān)系。通過NSOperation類中的addDependency方法铅辞,即可添加任務(wù)的之間的依賴關(guān)系厌漂。由于addDependency是NSOperation類中的方法,與隊(duì)列無關(guān)巷挥,因此也可以針對(duì)不同隊(duì)列中的任務(wù)設(shè)置任務(wù)執(zhí)行的先后依賴關(guān)系桩卵。
下方的示例中,有3個(gè)任務(wù)依次順序執(zhí)行倍宾,先依次下載兩張圖片雏节,圖片下載完成后,需要返回主線程去更新界面上的UIImageView高职,等圖片下載并刷新界面完成后钩乍,第三個(gè)任務(wù)是更新界面上的下載狀態(tài)Label。這3個(gè)任務(wù)的執(zhí)行有先后依賴關(guān)系怔锌。
- (IBAction)startBtnAction:(id)sender {
//創(chuàng)建兩個(gè)任務(wù)寥粹,兩個(gè)任務(wù)完成后,返回主線程執(zhí)行第三個(gè)更新Label的任務(wù)
NSBlockOperation *task1 = [NSBlockOperation blockOperationWithBlock:^{
//下載圖片
NSString *urlString = @"https://encrypted-tbn0.gstatic.com/images?q=tbn:ANd9GcRc3Rs3zHlmPEdusO8G_I1xHyKsYUujL9ZX76nfgkVVu69oU_gosw";
NSURL *url = [NSURL URLWithString:urlString];
NSData *imageData = [NSData dataWithContentsOfURL:url];
UIImage *image1 = [UIImage imageWithData:imageData];
NSOperationQueue *mainQueue = [NSOperationQueue mainQueue];
[mainQueue addOperationWithBlock:^{
self.imageView1.image = image1;
}];
}];
NSBlockOperation *task2 = [NSBlockOperation blockOperationWithBlock:^{
//下載圖片
NSString *urlString = @"https://encrypted-tbn1.gstatic.com/images?q=tbn:ANd9GcQ6RwzhikGicc2R-tiySq7A1K8g40apnXtryI31CO3JxW7IEIUJ_Q";
NSURL *url = [NSURL URLWithString:urlString];
NSData *imageData = [NSData dataWithContentsOfURL:url];
UIImage *image2 = [UIImage imageWithData:imageData];
NSOperationQueue *mainQueue = [NSOperationQueue mainQueue];
[mainQueue addOperationWithBlock:^{
self.imageView2.image = image2;
}];
}];
NSBlockOperation *task3 = [NSBlockOperation blockOperationWithBlock:^{
NSOperationQueue *mainQueue = [NSOperationQueue mainQueue];
[mainQueue addOperationWithBlock:^{
self.titleLab.text = @"下載完成";
}];
}];
//設(shè)置任務(wù)之間的執(zhí)行依賴關(guān)系
[task3 addDependency:task1];
[task3 addDependency:task2];
[task2 addDependency:task1];
//創(chuàng)建隊(duì)列
NSOperationQueue *queue = [[NSOperationQueue alloc] init];
//添加任務(wù)到隊(duì)列
[queue addOperation:task1];
[queue addOperation:task2];
[queue addOperation:task3];
}
四埃元、NSOperation與GCD的區(qū)別
- GCD是底層的C語言構(gòu)成的API涝涤,而NSOperationQueue及相關(guān)對(duì)象是Objc的對(duì)象。在GCD中岛杀,在隊(duì)列中執(zhí)行的是由block構(gòu)成的任務(wù)阔拳,這是一個(gè)輕量級(jí)的數(shù)據(jù)結(jié)構(gòu);而NSOperation作為一個(gè)對(duì)象类嗤,為我們提供了更多的選擇糊肠;
- 在NSOperationQueue中,我們可以隨時(shí)取消已經(jīng)設(shè)定要準(zhǔn)備執(zhí)行的任務(wù)(當(dāng)然遗锣,已經(jīng)開始的任務(wù)就無法阻止了)货裹,而GCD沒法停止已經(jīng)加入queue的block(其實(shí)是有的,但需要許多復(fù)雜的代碼)精偿;
- NSOperation能夠方便地設(shè)置依賴關(guān)系弧圆,我們可以讓一個(gè)Operation依賴于另一個(gè)Operation,這樣的話盡管兩個(gè)Operation處于同一個(gè)并行隊(duì)列中笔咽,但前者會(huì)直到后者執(zhí)行完畢后再執(zhí)行墓阀;
我們能將KVO應(yīng)用在NSOperation中,可以監(jiān)聽一個(gè)Operation是否完成或取消拓轻,這樣子能比GCD更加有效地掌控我們執(zhí)行的后臺(tái)任務(wù); - 在NSOperation中经伙,我們能夠設(shè)置NSOperation的priority優(yōu)先級(jí)扶叉,能夠使同一個(gè)并行隊(duì)列中的任務(wù)區(qū)分先后地執(zhí)行勿锅,而在GCD中,我們只能區(qū)分不同任務(wù)隊(duì)列的優(yōu)先級(jí)枣氧,如果要區(qū)分block任務(wù)的優(yōu)先級(jí)溢十,也需要大量的復(fù)雜代碼;
- 我們能夠?qū)SOperation進(jìn)行繼承达吞,在這之上添加成員變量與成員方法张弛,提高整個(gè)代碼的復(fù)用度,這比簡單地將block任務(wù)排入執(zhí)行隊(duì)列更有自由度酪劫,能夠在其之上添加更多自定制的功能吞鸭。