多線程編程-NSOperation

多線程編程-NSOperation

本文目錄前言一土全、NSInvocationOperation

二谱仪、NSBlockOperation

三掸读、NSOperation的其他用法四串远、自定義NSOperation回到頂部前言

1.上一講簡單介紹了NSThread的使用宏多,雖然也可以實現(xiàn)多線程編程,但是需要我們?nèi)ス芾砭€程的生命周期澡罚,還要考慮線程同步伸但、加鎖問題,造成一些性能上的開銷留搔。我們也可以配合使用NSOperation和NSOperationQueue實現(xiàn)多線程編程更胖,實現(xiàn)步驟大致是這樣的:

1> 先將需要執(zhí)行的操作封裝到一個NSOperation對象中

2> 然后將NSOperation對象添加到NSOperationQueue中

3> 系統(tǒng)會自動將NSOperation中封裝的操作放到一條新線程中執(zhí)行在此過程中,我們根本不用考慮線程的生命周期隔显、同步却妨、加鎖等問題下面列舉一個應用場景,比如微博的粉絲列表:每一行的頭像肯定要從新浪服務器下載圖片后才能顯示的括眠,而且是需要異步下載彪标。

這時候你就可以把每一行的圖片下載操作封裝到一個NSOperation對象中,上面有6行哺窄,所以要創(chuàng)建6個NSOperation對象捐下,然后添加到NSOperationQueue中,分別下載不同的圖片萌业,下載完畢后坷襟,回到對應的行將圖片顯示出來。?

2.默認情況下生年,NSOperation并不具備封裝操作的能力婴程,必須使用它的子類,使用NSOperation子類的方式有3種:

1> NSInvocationOperation

2> NSBlockOperation

3> 自定義子類繼承NSOperation抱婉,實現(xiàn)內(nèi)部相應的方法這講先介紹如何用NSOperation封裝一個操作档叔,后面再結合NSOperationQueue來使用。

?回到頂部一蒸绩、NSInvocationOperation

1 NSInvocationOperation *operation = [[[NSInvocationOperation alloc] initWithTarget:self selector:@selector(run:) object:@"mj"] autorelease];2 [operation start];

* 第1行初始化了一個NSInvocationOperation對象衙四,它是基于一個對象和selector來創(chuàng)建操作

* 第2行調(diào)用了start方法,緊接著會馬上執(zhí)行封裝好的操作患亿,也就是會調(diào)用self的run:方法传蹈,并且將@"mj"作為方法參數(shù)* 這里要注意:默認情況下,調(diào)用了start方法后并不會開一條新線程去執(zhí)行操作步藕,而是在當前線程同步執(zhí)行操作惦界。

只有將operation放到一個NSOperationQueue中,才會異步執(zhí)行操作咙冗。?

回到頂部二沾歪、NSBlockOperation

1.同步執(zhí)行一個操作1 NSBlockOperation *operation = [NSBlockOperation blockOperationWithBlock:^(){

2? ? ? ? NSLog(@"執(zhí)行了一個新的操作");

3 }];

4? // 開始執(zhí)行任務

5 [operation start];

* 第1行初始化了一個NSBlockOperation對象,它是用一個Block來封裝需要執(zhí)行的操作

* 第2行調(diào)用了start方法雾消,緊接著會馬上執(zhí)行Block中的內(nèi)容

* 這里還是在當前線程同步執(zhí)行操作灾搏,并沒有異步執(zhí)行?

2.并發(fā)執(zhí)行多個操作復制代碼?

1 NSBlockOperation *operation = [NSBlockOperation blockOperationWithBlock:^(){?

2NSLog(@"執(zhí)行第1次操作挫望,線程:%@", [NSThread currentThread]);?

3 }];?

5 [operation addExecutionBlock:^() {?

6NSLog(@"又執(zhí)行了1個新的操作,線程:%@", [NSThread currentThread]);

?7 }];?

?9 [operation addExecutionBlock:^() {

10 NSLog(@"又執(zhí)行了1個新的操作确镊,線程:%@", [NSThread currentThread]);11 }];

13 [operation addExecutionBlock:^() {

14NSLog(@"又執(zhí)行了1個新的操作士骤,線程:%@", [NSThread currentThread]);

15 }];

17 // 開始執(zhí)行任務

18 [operation start];復制代碼* 第1行初始化了一個NSBlockOperation對象* 分別在第5、9蕾域、13行通過addExecutionBlock:方法添加了新的操作拷肌,包括第1行的操作,一共封裝了4個操作* 在第18行調(diào)用start方法后旨巷,就會并發(fā)地執(zhí)行這4個操作巨缘,也就是會在不同線程中執(zhí)行1?

2013-02-02 21:38:46.102 thread[4602:c07] 又執(zhí)行了1個新的操作,線程:{name = (null), num = 1}

2 2013-02-02 21:38:46.102 thread[4602:3f03] 又執(zhí)行了1個新的操作采呐,線程:{name = (null), num = 5}

3 2013-02-02 21:38:46.102 thread[4602:1b03] 執(zhí)行第1次操作若锁,線程:{name = (null), num = 3}

4 2013-02-02 21:38:46.102 thread[4602:1303] 又執(zhí)行了1個新的操作,線程:{name = (null), num = 4}可以看出斧吐,每個操作所在線程的num值都不一樣又固,說明是不同線程 回到頂部三、NSOperation的其他用法

1.取消操作operation開始執(zhí)行之后, 默認會一直執(zhí)行操作直到完成煤率,我們也可以調(diào)用cancel方法中途取消操作[operation cancel];?

2.在操作完成后做一些事情如果想在一個NSOperation執(zhí)行完畢后做一些事情仰冠,就調(diào)用NSOperation的setCompletionBlock方法來設置想做的事情operation.completionBlock = ^() {? ? NSLog(@"執(zhí)行完畢");};

當operation封裝的操作執(zhí)行完畢后,就會回調(diào)Block里面的內(nèi)容 回到頂部四蝶糯、自定義NSOperation如果NSInvocationOperation和NSBlockOperation不能滿足需求洋只,我們可以直接新建子類繼承NSOperation,并添加任何需要執(zhí)行的操作昼捍。如果只是簡單地自定義NSOperation识虚,只需要重載-(void)main這個方法,在這個方法里面添加需要執(zhí)行的操作妒茬。下面寫個子類DownloadOperation來下載圖片

1.繼承NSOperation担锤,重寫main方法DownloadOperation.h復制代碼

#import

@protocol DownloadOperationDelegate;

@interface DownloadOperation : NSOperation

// 圖片的url路徑

@property (nonatomic, copy) NSString *imageUrl;

// 代理@property (nonatomic, assign) iddelegate;

- (id)initWithUrl:(NSString *)url delegate:(id)delegate;@end

// 圖片下載的協(xié)議

@protocol DownloadOperationDelegate

- (void)downloadFinishWithImage:(UIImage *)image;

@end復制代碼DownloadOperation.m復制代碼?

1 #import "DownloadOperation.h"

?3 @implementation DownloadOperation?

4 @synthesize delegate = _delegate;?

5 @synthesize imageUrl = _imageUrl;?

6 // 初始化

8 - (id)initWithUrl:(NSString *)url delegate:(id)delegate {

9? ? if (self = [super init]) {

10? ? ? ? self.imageUrl = url;

11? ? ? ? self.delegate = delegate;

12? ? }

13? ? return self;

14 }

15 // 釋放內(nèi)存

16 - (void)dealloc {

17? ? [super dealloc];

18? ? [_imageUrl release];

19 }

21 // 執(zhí)行主任務

22 - (void)main {

23? ? // 新建一個自動釋放池,如果是異步執(zhí)行操作乍钻,那么將無法訪問到主線程的自動釋放池

24? ? @autoreleasepool {

25? ? ? ? // ....

26? ? }

27 }

28 @end

復制代碼

* 在第22行重載了main方法妻献,等會就把下載圖片的代碼寫到這個方法中

* 如果這個DownloadOperation是在異步線程中執(zhí)行操作,也就是說main方法在異步線程調(diào)用团赁,那么將無法訪問主線程的自動釋放池,所以在第24行創(chuàng)建了一個屬于當前線程的自動釋放池

2.正確響應取消事件

* 默認情況下谨履,一個NSOperation開始執(zhí)行之后欢摄,會一直執(zhí)行任務到結束,就比如上面的DownloadOperation笋粟,默認會執(zhí)行完main方法中的所有代碼怀挠。

* NSOperation提供了一個cancel方法析蝴,可以取消當前的操作。

* 如果是自定義NSOperation的話绿淋,需要手動處理這個取消事件闷畸。比如,一旦調(diào)用了cancel方法立肘,應該馬上終止main方法的執(zhí)行熏兄,并及時回收一些資源背伴。

* 處理取消事件的具體做法是:在main方法中定期地調(diào)用isCancelled方法檢測操作是否已經(jīng)被取消,也就是說是否調(diào)用了cancel方法殿漠,如果返回YES,表示已取消佩捞,則立即讓main方法返回绞幌。

* 以下地方可能需要調(diào)用isCancelled方法:

在執(zhí)行任何實際的工作之前,也就是在main方法的開頭一忱。因為取消可能發(fā)生在任何時候莲蜘,甚至在operation執(zhí)行之前。

執(zhí)行了一段耗時的操作之后也需要檢測操作是否已經(jīng)被取消

復制代碼

1 - (void)main {

2? ? // 新建一個自動釋放池帘营,如果是異步執(zhí)行操作票渠,那么將無法訪問到主線程的自動釋放池

3? ? @autoreleasepool {

4? ? ? ? if (self.isCancelled) return;

5

6? ? ? ? // 獲取圖片數(shù)據(jù)

7? ? ? ? NSURL *url = [NSURL URLWithString:self.imageUrl];

8? ? ? ? NSData *imageData = [NSData dataWithContentsOfURL:url];

9

10? ? ? ? if (self.isCancelled) {

11? ? ? ? ? ? url = nil;

12? ? ? ? ? ? imageData = nil;

13? ? ? ? ? ? return;

14? ? ? ? }

15

16? ? ? ? // 初始化圖片

17? ? ? ? UIImage *image = [UIImage imageWithData:imageData];

18

19? ? ? ? if (self.isCancelled) {

20? ? ? ? ? ? image = nil;

21? ? ? ? ? ? return;

22? ? ? ? }

23

24? ? ? ? if ([self.delegate respondsToSelector:@selector(downloadFinishWithImage:)]) {

25? ? ? ? ? ? // 把圖片數(shù)據(jù)傳回到主線程

26? ? ? ? ? ? [(NSObject *)self.delegate performSelectorOnMainThread:@selector(downloadFinishWithImage:) withObject:image waitUntilDone:NO];

27? ? ? ? }

28? ? }

29 }

復制代碼

* 在第4行main方法的開頭就先判斷operation有沒有被取消。如果被取消了仪吧,那就沒有必要往下執(zhí)行了

* 經(jīng)過第8行下載圖片后庄新,在第10行也需要判斷操作有沒有被取消

* 總之,執(zhí)行了一段比較耗時的操作之后薯鼠,都需要判斷操作有沒有被取消

* 圖片下載完畢后择诈,在第26行將圖片數(shù)據(jù)傳遞給了代理(delegate)對象

最后編輯于
?著作權歸作者所有,轉載或內(nèi)容合作請聯(lián)系作者
  • 序言:七十年代末,一起剝皮案震驚了整個濱河市出皇,隨后出現(xiàn)的幾起案子羞芍,更是在濱河造成了極大的恐慌,老刑警劉巖郊艘,帶你破解...
    沈念sama閱讀 212,816評論 6 492
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件荷科,死亡現(xiàn)場離奇詭異,居然都是意外死亡纱注,警方通過查閱死者的電腦和手機畏浆,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 90,729評論 3 385
  • 文/潘曉璐 我一進店門,熙熙樓的掌柜王于貴愁眉苦臉地迎上來狞贱,“玉大人刻获,你說我怎么就攤上這事∠规遥” “怎么了蝎毡?”我有些...
    開封第一講書人閱讀 158,300評論 0 348
  • 文/不壞的土叔 我叫張陵厚柳,是天一觀的道長。 經(jīng)常有香客問我沐兵,道長别垮,這世上最難降的妖魔是什么? 我笑而不...
    開封第一講書人閱讀 56,780評論 1 285
  • 正文 為了忘掉前任扎谎,我火速辦了婚禮碳想,結果婚禮上,老公的妹妹穿的比我還像新娘簿透。我一直安慰自己移袍,他們只是感情好,可當我...
    茶點故事閱讀 65,890評論 6 385
  • 文/花漫 我一把揭開白布老充。 她就那樣靜靜地躺著葡盗,像睡著了一般。 火紅的嫁衣襯著肌膚如雪啡浊。 梳的紋絲不亂的頭發(fā)上觅够,一...
    開封第一講書人閱讀 50,084評論 1 291
  • 那天,我揣著相機與錄音巷嚣,去河邊找鬼喘先。 笑死,一個胖子當著我的面吹牛廷粒,可吹牛的內(nèi)容都是我干的窘拯。 我是一名探鬼主播,決...
    沈念sama閱讀 39,151評論 3 410
  • 文/蒼蘭香墨 我猛地睜開眼坝茎,長吁一口氣:“原來是場噩夢啊……” “哼涤姊!你這毒婦竟也來了?” 一聲冷哼從身側響起嗤放,我...
    開封第一講書人閱讀 37,912評論 0 268
  • 序言:老撾萬榮一對情侶失蹤思喊,失蹤者是張志新(化名)和其女友劉穎,沒想到半個月后次酌,有當?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體恨课,經(jīng)...
    沈念sama閱讀 44,355評論 1 303
  • 正文 獨居荒郊野嶺守林人離奇死亡,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點故事閱讀 36,666評論 2 327
  • 正文 我和宋清朗相戀三年岳服,在試婚紗的時候發(fā)現(xiàn)自己被綠了剂公。 大學時的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片。...
    茶點故事閱讀 38,809評論 1 341
  • 序言:一個原本活蹦亂跳的男人離奇死亡吊宋,死狀恐怖诬留,靈堂內(nèi)的尸體忽然破棺而出,到底是詐尸還是另有隱情,我是刑警寧澤文兑,帶...
    沈念sama閱讀 34,504評論 4 334
  • 正文 年R本政府宣布,位于F島的核電站腺劣,受9級特大地震影響绿贞,放射性物質(zhì)發(fā)生泄漏。R本人自食惡果不足惜橘原,卻給世界環(huán)境...
    茶點故事閱讀 40,150評論 3 317
  • 文/蒙蒙 一籍铁、第九天 我趴在偏房一處隱蔽的房頂上張望。 院中可真熱鬧趾断,春花似錦拒名、人聲如沸。這莊子的主人今日做“春日...
    開封第一講書人閱讀 30,882評論 0 21
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽。三九已至脐帝,卻和暖如春同云,著一層夾襖步出監(jiān)牢的瞬間,已是汗流浹背堵腹。 一陣腳步聲響...
    開封第一講書人閱讀 32,121評論 1 267
  • 我被黑心中介騙來泰國打工炸站, 沒想到剛下飛機就差點兒被人妖公主榨干…… 1. 我叫王不留,地道東北人疚顷。 一個月前我還...
    沈念sama閱讀 46,628評論 2 362
  • 正文 我出身青樓旱易,卻偏偏與公主長得像,于是被迫代替她去往敵國和親腿堤。 傳聞我的和親對象是個殘疾皇子阀坏,可洞房花燭夜當晚...
    茶點故事閱讀 43,724評論 2 351

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