在開發(fā)的時候 因為沒有好好去了解三者的差異性 一時貪圖便捷 一味使用NSThread開啟異步線程 線程爆滿沒有及時關(guān)閉銷毀 挖了坑吃了虧。
今天就在這里簡單寫寫三個的用法和差異性:
NSThread 封裝性最差,主要基于thread使用,方便使用,缺點是需要手動關(guān)閉;
GCD基于C的API,代碼看起來比較亂(高大上),主要基于task使用;
NSOperation是基于GCD,被封裝成NSObject對象使用,主要基于隊列使用。
NSThread的使用
NSThread 方法
1.創(chuàng)建:
//需要手動開啟 NSThread *thread = [[NSThread alloc] initWithTarget:self selector:@selector(run) object:nil]; [thread start];
//或 自動開啟線程 [NSThread detachNewThreadSelector:@selector(run) toTarget:self withObject:nil];
//或 隱式創(chuàng)建并開啟線程 [self performSelectorInBackground:@selector(run) withObject:nil];
②獲取主線程和判斷是否為主線程
+ (NSThread *)mainThread; // 獲得主線程 - (BOOL)isMainThread; // 是否為主線程 + (BOOL)isMainThread; // 是否為主線程
③或許當前線程和線程名稱
NSThread *current = [NSThread currentThread]; - (void)setName:(NSString *)name;
④線程中的通信 線程A跳去線程B
//選擇主線程 - (void)performSelectorOnMainThread:(SEL)aSelector withObject:(id)arg waitUntilDone:(BOOL)wait; //選擇特定線程 - (void)performSelector:(SEL)aSelector onThread:(NSThread *)thr withObject:(id)arg waitUntilDone:(BOOL)wait;
⑤回到主線程更新UI
[self performSelectorOnMainThread:@selector(appendTextView:) withObject:message waitUntilDone:YES];
⑥線程睡眠
+ (void)sleepUntilDate:(NSDate *)date; + (void)sleepForTimeInterval:(NSTimeInterval)ti;
⑦NSThread 線程取消和線程銷毀
線程取消- (void)cancel;
實際上只是把isCancel狀態(tài)置為YES,沒有實際上銷毀線程。要實現(xiàn)取消的功能,我們需要自己在線程的main函數(shù)中定期檢查isCancelled狀態(tài)來判斷線程是否需要退出,當isCancelled為YES的時候,我們手動退出。如果我們沒有在main函數(shù)中檢查isCancelled狀態(tài),那么調(diào)用-cancel將沒有任何意義。
線程銷毀 - (void)exit;
個會立即終止線程,即使任務(wù)沒有完成。有可能導致內(nèi)存泄漏等。
注意:對于有runloop的線程,可以使用CFRunLoopStop()結(jié)束runloop配合-cancel結(jié)束線程
runloop啟動的方法中run和runUntilDate:都無法使用CFRunLoopStop()退出,只有runMode:beforeDate:可以響應(yīng)CFRunLoopStop(),所以要想使用CFRunLoopStop()退出runloop,必須使用runMode:beforeDate:啟動
NSThread 完整例子
- (void)viewDidLoad{ // ①創(chuàng)建線程 b并指定方法threadTest self.thread = [[NSThread alloc] initWithTarget:self selector:@selector(threadTest) object:nil]; //②在線程啟動之前設(shè)置線程優(yōu)先級 self.thread.qualityOfService = NSQualityOfServiceDefault; //③啟動線程 [self.thread start]; } /*由于線程的創(chuàng)建和銷毀非常消耗性能,大多情況下,我們需要復(fù)用一個長期運行的線程來執(zhí)行任務(wù)。在線程啟動之后會首先執(zhí)行-threadStar,正常情況下threadStar方法執(zhí)行結(jié)束之后,線程就會退出。為了線程可以長期復(fù)用接收消息,我們需要在threadStar中給thread添加runloop*/ - (void)threadStar{ // ①給線程設(shè)置名字 [[NSThread currentThread] setName:@"myThread"]; // ②給線程添加runloop NSRunLoop *runLoop = [NSRunLoop currentRunLoop]; //③給runloop添加數(shù)據(jù)源 [runLoop addPort:[NSMachPort port] forMode:NSDefaultRunLoopMode]; //④:檢查isCancelled while (![[NSThread currentThread] isCancelled]) { //⑤啟動runloop [runLoop runMode:NSDefaultRunLoopMode beforeDate:[NSDate dateWithTimeIntervalSinceNow:10]]; } }
- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
- 9
- 10
- 11
- 12
- 13
- 14
- 15
- 16
- 17
- 18
- 19
- 20
- 21
- 22
- 23
- 24
- 25
- 26
- 27
- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
- 9
- 10
- 11
- 12
- 13
- 14
- 15
- 16
- 17
- 18
- 19
- 20
- 21
- 22
- 23
- 24
- 25
- 26
- 27
①:設(shè)置線程的名字,這一步不是必須的,主要是為了debug的時候更方便,可以直接看出這是哪個線程
②:自定義的線程默認是沒有runloop的,調(diào)用-currentRunLoop,方法內(nèi)部會為線程創(chuàng)建runloop
③:如果沒有數(shù)據(jù)源,runloop會在啟動之后會立刻退出。所以需要給runloop添加一個數(shù)據(jù)源,這里添加的是NSPort數(shù)據(jù)源
④:定期檢查isCancelled,當外部調(diào)用-cancel方法將isCancelled置為YES的時候,線程可以退出
⑤:啟動runloop
在耗時操作中再次使用self.thread,這里把耗時操作loadImage扔給它去做:
[self performSelector:@selector(loadImage) onThread:self.thread withObject:nil waitUntilDone:NO]
最后,當你想要結(jié)束這個線程的時候,使用CFRunLoopStop()配合-cancel來結(jié)束線程:
//在self.thread內(nèi)部直接調(diào)用cancelThread方法 //在其他線程則用[self performSelector:@selector(cancelThread) onThread:self.thread withObject:nil waitUntilDone:NO] - (void)cancelThread { [[NSThread currentThread] cancel]; CFRunLoopStop(CFRunLoopGetCurrent()); }
GCD的使用
1?⃣獲取一個全局隊列
dispatch_queue_t aQueue = dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0); /* 全局隊列的四種類型: DISPATCH_QUEUE_PRIORITY_HIGH DISPATCH_QUEUE_PRIORITY_DEFAULT DISPATCH_QUEUE_PRIORITY_LOW DISPATCH_QUEUE_PRIORITY_BACKGROUND //等待所有比它級別高的隊列中的任務(wù)執(zhí)行完或CPU空閑的時候才會執(zhí)行自己的任務(wù) */
① 創(chuàng)建串行隊列/并發(fā)隊列
//串行隊列 dispatch_queue_t serialQueue; serialQueue = dispatch_queue_create("com.example.SerialQueue", NULL); //并發(fā)隊列 dispatch_queue_t concurrentQueue; concurrentQueue = dispatch_queue_create("com.example.ConcurrentQueue", DISPATCH_QUEUE_CONCURRENT);
②獲取主隊列
dispatch_queue_t mainQueue; mainQueue = dispatch_get_main_queue();
③添加到任務(wù)隊列執(zhí)行操作
//異步執(zhí)行 dispatch_queue_t myCustomQueue; myCustomQueue = dispatch_queue_create("com.example.MyCustomQueue", NULL); dispatch_async(myCustomQueue, ^{ NSLog("Do some work here."); }); //同步執(zhí)行 dispatch_sync(myCustomQueue, ^{ NSLog("Do some more work here."); });
posted on 2016-11-04 23:32
聶文龍 閱讀(313)
評論(0) 編輯 收藏 引用