iOS 多線程實現(xiàn)- NSOperation

一粪滤、介紹

NSOperation是一個抽象類,可以使用系統(tǒng)提供的子類或者自己實現(xiàn)它的子類,來完成多線程隧熙。我們平時提到的NSOperation就默認包含了它的子類,具有以下特性:
1幻林、是OC語言中基于GCD的面向對象的封裝贞盯;
2、使用起來比GCD更加簡單(面向對象)滋将;
3邻悬、提供了一些用GCD不好實現(xiàn)的功能,比如可以取消在任務處理隊列中的任務随闽,添加任務間的依賴關系等等父丰;
4、蘋果推薦使用,使用NSOperation不用關心線程以及線程的生命周期掘宪;
5蛾扇、可以指定操作之間的依賴關系,是將操作添加到隊列魏滚。
6镀首、并發(fā)隊列,異步執(zhí)行(多個線程鼠次,無序執(zhí)行)更哄。

NSOperation方便統(tǒng)一管理,適用一些大型的復雜的場合腥寇,比如我們常用的網絡框架:AFNetworking成翩、SDWebImage等等。

二赦役、NSOperation 和 NSOperationQueue 實現(xiàn)多線程的步驟

1麻敌、先將需要執(zhí)行的操作封裝到一個 NSOperation 對象中
2、然后將 NSOperation 對象添加到 NSOperationQueue 中
3掂摔、系統(tǒng)會自動將 NSOperationQueue 中的 NSOperation 取出來
4术羔、講取出來的 NSOperation 封裝的操作放到一條新線程中執(zhí)行

三赢赊、NSOperation 的子類

NSOperation是一個抽象類,并不具備封裝操作的能力, 必須要使用它的子類
實現(xiàn)NSOperation子類的方式有3種:
1级历、NSInvocationOperation:較少使用释移;
2、NSBlockOperation:最常使用鱼喉;
3秀鞭、自定義子類繼承NSOperation,實現(xiàn)內部相應的方法:很少使用扛禽。
我們要做的就是將以上3種操作的任意一種添加到NSOperationQueue來使用锋边。

1、NSInvocationOperation

1.1编曼、直接執(zhí)行操作(同步)
- (void)touchesBegan:(NSSet *)touches withEvent:(UIEvent *)event {
    [self invocationOperationTest];
}

//創(chuàng)建一個操作并執(zhí)行
- (void)invocationOperationTest {
    // 創(chuàng)建操作(最后的object參數(shù)是傳遞給selector方法的參數(shù))
    NSInvocationOperation *operation = [[NSInvocationOperation alloc] initWithTarget:self selector:@selector(demo:) object:@"這是一個參數(shù)"];
    [operation start];
}
// 將參數(shù)與當前線程打印
- (void)demo:(NSString *)str {
    NSLog(@"%@--%@",str,[NSThread currentThread]);
}

/*************************執(zhí)行結果****************************/
2017-09-07 10:43:53.594 TextDemo[1074:374562] 這是一個參數(shù)--<NSThread: 0x6100000729c0>{number = 1, name = main}

創(chuàng)建初始化一個NSInvocationOperation對象豆巨,并且根據一個對象(self)selector來創(chuàng)建操作,默認情況下掐场,調用了start方法后并不會開一條新線程去執(zhí)行操作往扔,而是在當前線程同步執(zhí)行操作。

1.2熊户、將操作添加到NSOperationQueue執(zhí)行
- (void)touchesBegan:(NSSet *)touches withEvent:(UIEvent *)event {
    [self invocationOperationTest];
}
// 將操作添加到隊列
- (void)invocationOperationTest {
    // 創(chuàng)建操作(最后的object參數(shù)是傳遞給selector方法的參數(shù))
    NSInvocationOperation *operation = [[NSInvocationOperation alloc] initWithTarget:self selector:@selector(demo:) object:@"這是一個參數(shù)"];
    
    // 創(chuàng)建操作隊列
    NSOperationQueue *operationQueue = [[NSOperationQueue alloc] init];
    
    // 將操作添加到操作隊列
    [operationQueue addOperation:operation];
}
// 將參數(shù)與當前線程打印
- (void)demo:(NSString *)str {
    NSLog(@"%@--%@",str,[NSThread currentThread]);
}

/*************************執(zhí)行結果****************************/
2017-09-07 10:51:13.312 TextDemo[1161:423494] 這是一個參數(shù)--<NSThread: 0x600000078740>{number = 4, name = (null)}

根據打印結果萍膛,可以看出新開啟了一個線程執(zhí)行操作,且是異步執(zhí)行的嚷堡。

2蝗罗、NSBlockOperation

2.1、執(zhí)行一個操作(同步)
- (void)touchesBegan:(NSSet *)touches withEvent:(UIEvent *)event {
    [self blcokOperationText];
}

- (void)blcokOperationText
{
    NSBlockOperation *operation = [NSBlockOperation blockOperationWithBlock:^{
        NSLog(@"1:%@", [NSThread currentThread]);
    }];
    [operation start];
}

/*************************執(zhí)行結果****************************/
2017-09-07 11:01:31.491 TextDemo[1258:484332] 1:<NSThread: 0x600000066b80>{number = 1, name = main}

可以看到這種方法非常簡單蝌戒,有點類似于GCD串塑,它也是同步執(zhí)行的。

2.2北苟、添加多個操作執(zhí)行(異步)
- (void)touchesBegan:(NSSet *)touches withEvent:(UIEvent *)event {
    [self blcokOperationText];
}

- (void)blcokOperationText
{
    NSBlockOperation *operation = [NSBlockOperation blockOperationWithBlock:^{
        NSLog(@"1:%@", [NSThread currentThread]);
    }];
    
    // 再添加3操作
    [operation addExecutionBlock:^() {
        NSLog(@"2:%@", [NSThread currentThread]);
    }];
    [operation addExecutionBlock:^() {
        NSLog(@"3:%@", [NSThread currentThread]);
    }];
    [operation addExecutionBlock:^() {
        NSLog(@"4:%@", [NSThread currentThread]);
    }];
    
    [operation start];
}

/*************************執(zhí)行結果****************************/
2017-09-07 11:02:50.342 TextDemo[1290:497642] 1:<NSThread: 0x61800006d740>{number = 1, name = main}
2017-09-07 11:02:50.343 TextDemo[1290:497642] 3:<NSThread: 0x61800006d740>{number = 1, name = main}
2017-09-07 11:02:50.343 TextDemo[1290:497642] 4:<NSThread: 0x61800006d740>{number = 1, name = main}
2017-09-07 11:02:50.343 TextDemo[1290:497983] 2:<NSThread: 0x618000071240>{number = 5, name = (null)}

當添加多個操作時桩匪,開啟新線程異步執(zhí)行。

2.3友鼻、將操作添加到NSOperationQueue執(zhí)行
- (void)touchesBegan:(NSSet *)touches withEvent:(UIEvent *)event {
    [self blcokOperationText];
}

- (void)blcokOperationText
{
    NSBlockOperation *operation = [NSBlockOperation blockOperationWithBlock:^{
        NSLog(@"1:%@", [NSThread currentThread]);
    }];
    
    // 再添加3操作
    [operation addExecutionBlock:^() {
        NSLog(@"2:%@", [NSThread currentThread]);
    }];
    [operation addExecutionBlock:^() {
        NSLog(@"3:%@", [NSThread currentThread]);
    }];
    [operation addExecutionBlock:^() {
        NSLog(@"4:%@", [NSThread currentThread]);
    }];
    
    NSOperationQueue *queue = [[NSOperationQueue alloc]init];
    [queue addOperation:operation];
    
}

/*************************執(zhí)行結果****************************/
2017-09-07 11:07:40.347 TextDemo[1354:525108] 1:<NSThread: 0x61800007ab00>{number = 3, name = (null)}
2017-09-07 11:07:40.347 TextDemo[1354:525105] 4:<NSThread: 0x6100002600c0>{number = 5, name = (null)}
2017-09-07 11:07:40.347 TextDemo[1354:525106] 2:<NSThread: 0x610000261480>{number = 4, name = (null)}
2017-09-07 11:07:40.347 TextDemo[1354:525126] 3:<NSThread: 0x61000007fec0>{number = 6, name = (null)}

根據打印結果傻昙,可以看出新開啟了多個線程執(zhí)行操作,且是異步執(zhí)行的彩扔。

3屋匕、自定義Operation

自定義NSOperation最主要的就是重載-(void)main這個方法,在這個方法里面添加需要執(zhí)行的操作借杰。當執(zhí)行這個操作時,系統(tǒng)會自動調用-(void)main這個方法进泼。

#import "CustomOpertaionTest.h"

@implementation CustomOpertaionTest
- (void)main {
    // 新建一個自動釋放池蔗衡,避免內存泄露
    @autoreleasepool {
        // 執(zhí)行的代碼
        NSLog(@"這是一個測試:%@",[NSThread currentThread]);
    }
}
@end

在主控制器中調用纤虽,一共兩種:一種同步一種異步

//1、直接執(zhí)行绞惦,同步
CustomOpertaionTest *operation = [[CustomOpertaionTest alloc] init];
[operation start];

/*************************執(zhí)行結果****************************/
2017-09-07 11:13:25.149 TextDemo[1354:562140] 這是一個測試:<NSThread: 0x7ff420d28000>{number = 1, name = main}
//2逼纸、添加到隊列,異步
CustomOpertaionTest *operation = [[CustomOpertaionTest alloc] init];
NSOperationQueue *operationQueue = [[NSOperationQueue alloc] init];
[operationQueue addOperation:operation];

/*************************執(zhí)行結果****************************/
2017-09-07 11:14:30.500 TextDemo[1354:571046] 這是一個測試:<NSThread: 0x7ff2d0539d70>{number = 2, name = (null)}

四济蝉、NSOperation其它常用方法

1杰刽、取消操作

operation開始執(zhí)行之后, 默認會一直執(zhí)行操作直到完成,我們也可以調用cancel方法中途取消操作

[operation cancel];

這里有一個問題王滤,我們自定義的operation贺嫂,如果支持取消,則應該在重載的main函數(shù)中查詢用戶是否取消了操作雁乡,特別是main函數(shù)中又循環(huán)的時候一定要查詢第喳。然后釋放資源,退出main函數(shù)踱稍。

另外開啟新線程后注意內存管理曲饱,最好在main函數(shù)里面的最外層創(chuàng)建自動釋放池,保證每一個消息循環(huán)都能釋放內存

- (void)main {
    // 新建一個自動釋放池珠月,避免內存泄露
    @autoreleasepool {
        // 執(zhí)行的代碼
        NSLog(@"這是一個測試:%@",[NSThread currentThread]);
    }
}

2扩淀、NSOperation執(zhí)行完畢后操作

operation.completionBlock = ^() {
    // 所有操作執(zhí)行完成后執(zhí)行
};

3、設置最大并發(fā)數(shù)

默認情況最大并發(fā)數(shù)為6啤挎,即同時最多只允許6個線程處于就緒態(tài)驻谆。設置最大并發(fā)數(shù)為1時,程序將串行執(zhí)行

// 最大并發(fā)數(shù)為3
[operationQueue setMaxConcurrentOperationCount:3];

4侵浸、設置依賴

設置依賴來保證執(zhí)行順序旺韭,?如一定要讓操作A執(zhí)行完后,才能執(zhí)行操作B,可以像下面這么寫:

[operationB addDependency:operationA];

但是一定要注意不要A依賴B,然后B又依賴A掏觉,這樣A和B相互依賴造成都不能得到執(zhí)行区端。
如果A和B處于不同的操作隊列,也是可以設置依賴關系的澳腹。

最后編輯于
?著作權歸作者所有,轉載或內容合作請聯(lián)系作者
  • 序言:七十年代末织盼,一起剝皮案震驚了整個濱河市,隨后出現(xiàn)的幾起案子酱塔,更是在濱河造成了極大的恐慌沥邻,老刑警劉巖,帶你破解...
    沈念sama閱讀 217,084評論 6 503
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件羊娃,死亡現(xiàn)場離奇詭異唐全,居然都是意外死亡,警方通過查閱死者的電腦和手機,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 92,623評論 3 392
  • 文/潘曉璐 我一進店門邮利,熙熙樓的掌柜王于貴愁眉苦臉地迎上來弥雹,“玉大人,你說我怎么就攤上這事延届〖粑穑” “怎么了?”我有些...
    開封第一講書人閱讀 163,450評論 0 353
  • 文/不壞的土叔 我叫張陵方庭,是天一觀的道長厕吉。 經常有香客問我,道長械念,這世上最難降的妖魔是什么头朱? 我笑而不...
    開封第一講書人閱讀 58,322評論 1 293
  • 正文 為了忘掉前任,我火速辦了婚禮订讼,結果婚禮上髓窜,老公的妹妹穿的比我還像新娘。我一直安慰自己欺殿,他們只是感情好寄纵,可當我...
    茶點故事閱讀 67,370評論 6 390
  • 文/花漫 我一把揭開白布。 她就那樣靜靜地躺著脖苏,像睡著了一般程拭。 火紅的嫁衣襯著肌膚如雪。 梳的紋絲不亂的頭發(fā)上棍潘,一...
    開封第一講書人閱讀 51,274評論 1 300
  • 那天恃鞋,我揣著相機與錄音,去河邊找鬼亦歉。 笑死恤浪,一個胖子當著我的面吹牛,可吹牛的內容都是我干的肴楷。 我是一名探鬼主播水由,決...
    沈念sama閱讀 40,126評論 3 418
  • 文/蒼蘭香墨 我猛地睜開眼,長吁一口氣:“原來是場噩夢啊……” “哼赛蔫!你這毒婦竟也來了砂客?” 一聲冷哼從身側響起,我...
    開封第一講書人閱讀 38,980評論 0 275
  • 序言:老撾萬榮一對情侶失蹤呵恢,失蹤者是張志新(化名)和其女友劉穎鞠值,沒想到半個月后,有當?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體渗钉,經...
    沈念sama閱讀 45,414評論 1 313
  • 正文 獨居荒郊野嶺守林人離奇死亡彤恶,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內容為張勛視角 年9月15日...
    茶點故事閱讀 37,599評論 3 334
  • 正文 我和宋清朗相戀三年,在試婚紗的時候發(fā)現(xiàn)自己被綠了。 大學時的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片声离。...
    茶點故事閱讀 39,773評論 1 348
  • 序言:一個原本活蹦亂跳的男人離奇死亡歇竟,死狀恐怖,靈堂內的尸體忽然破棺而出抵恋,到底是詐尸還是另有隱情,我是刑警寧澤宝磨,帶...
    沈念sama閱讀 35,470評論 5 344
  • 正文 年R本政府宣布弧关,位于F島的核電站,受9級特大地震影響唤锉,放射性物質發(fā)生泄漏世囊。R本人自食惡果不足惜,卻給世界環(huán)境...
    茶點故事閱讀 41,080評論 3 327
  • 文/蒙蒙 一窿祥、第九天 我趴在偏房一處隱蔽的房頂上張望株憾。 院中可真熱鬧,春花似錦晒衩、人聲如沸嗤瞎。這莊子的主人今日做“春日...
    開封第一講書人閱讀 31,713評論 0 22
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽贝奇。三九已至,卻和暖如春靠胜,著一層夾襖步出監(jiān)牢的瞬間掉瞳,已是汗流浹背。 一陣腳步聲響...
    開封第一講書人閱讀 32,852評論 1 269
  • 我被黑心中介騙來泰國打工浪漠, 沒想到剛下飛機就差點兒被人妖公主榨干…… 1. 我叫王不留陕习,地道東北人。 一個月前我還...
    沈念sama閱讀 47,865評論 2 370
  • 正文 我出身青樓址愿,卻偏偏與公主長得像该镣,于是被迫代替她去往敵國和親。 傳聞我的和親對象是個殘疾皇子必盖,可洞房花燭夜當晚...
    茶點故事閱讀 44,689評論 2 354

推薦閱讀更多精彩內容