多線程的主要是用來執行一些耗時操作,例如網絡圖片、視頻、歌曲、書籍等資源下載,游戲中的音樂播放等,充分發揮多核處理器的優勢,並發(同時執行)任務讓系統運行的更快、更流暢。
介紹下比較常用的多線程技術, 主要有NSObject、NSThread、NSOperation、GCD等。
1、 NSObject多線程技術
1> 使用performSelectorInBackground可以開啟後台線程,執行selector選擇器選擇的方法
2> 使用performSelectorOnMainThread可以重新回到主線程執行任務,通常用於後台線程更新界面UI時使用
3> [NSThread sleepForTimeInterval:1.0f]; 讓當前線程休眠,通常在程序開發中,用於模擬耗時操作,以便跟蹤不同的並發執行情況!
但是,在程序發布時,千萬不要保留此方法!不要把測試中的代碼交給客戶,否則會造成不好的用戶體驗。
提示:使用performSelectorInBackground也可以直接修改UI,但是強烈不建議使用。修改UI最好在主線程中執行
注意:在使用NSThread或者NSObject的線程方法時,一定要使用自動釋放池,否則容易出現內存洩露。
復制代碼
1 - (void)viewDidLoad
2 {
3 [super viewDidLoad];
4
5 // 在後台線程執行方法
6 [self performSelectorInBackground:@selector(testObject) withObject:nil];
7
8 // 打印當前線程num
9 NSLog(@"main - %@", [NSThread currentThread]);
10 }
11
12 - (void)testObject
13 {
14 // 自動釋放池,避免出現內存洩露
15 @autoreleasepool {
16
17 // 讓當前線程睡眠 2.0 秒
18 [NSThread sleepForTimeInterval:2.0f];
19
20 // 打印當前線程
21 NSLog(@"Background - %@", [NSThread currentThread]);
22 }
23 }
復制代碼
2、NSThread多線程技術
1> 類方法直接開啟後台線程,並執行選擇器方法
detachNewThreadSelector
2> 成員方法,在實例化線程對象之後,需要使用start執行選擇器方法
initWithTarget
對於NSThread的簡單使用,可以用NSObject的performSelectorInBackground替代
同時,在NSThread調用的方法中,同樣要使用autoreleasepool進行內存管理,否則容易出現內存洩露。
復制代碼
1 - (void)viewDidLoad
2 {
3 [super viewDidLoad];
4
5 // 開啟新線程執行方法
6 [NSThread detachNewThreadSelector:@selector(testObject) toTarget:self withObject:nil];
7
8 // // 通過實例化一個線程來開啟任務
9 // NSThread *thread = [[NSThread alloc] initWithTarget:self selector:@selector(testObject) object:nil];
10 //
11 // [thread start];
12
13 // 打印當前線程num
14 NSLog(@"main - %@", [NSThread currentThread]);
15 }
16
17 - (void)testObject
18 {
19 // 自動釋放池,避免出現內存洩露
20 @autoreleasepool {
21
22 // 讓當前線程睡眠 2.0 秒
23 [NSThread sleepForTimeInterval:2.0f];
24
25 // 打印當前線程
26 NSLog(@"Background - %@", [NSThread currentThread]);
27 }
28 }
復制代碼
3、NSOperation多線程技術
1> 使用步驟:
1) 實例化操作
a) NSInvocationOperation
b) NSBlockOperation
2) 將操作添加到隊列NSOperationQueue即可啟動多線程執行
2> 更新UI使用主線程隊列
[NSOpeationQueue mainQueue] addOperation ^{};
3> 操作隊列的setMaxConcurrentOperationCount
可以設置同時並發的線程數量!
提示:此功能僅有NSOperation有!
4> 使用addDependency可以設置任務的執行先後順序,同時可以跨操作隊列指定依賴關系
提示:在指定依賴關系時,注意不要循環依賴,否則不工作。
復制代碼
1 @interface FLViewController ()
2 {
3 NSOperationQueue *_queue;
4 }
5 @end
6
7 @implementation FLViewController
8
9 - (void)viewDidLoad
10 {
11 [super viewDidLoad];
12
13 // 1. 初始化操作隊列
14 _queue = [[NSOperationQueue alloc] init];
15
16 // 2. 創建線程操作
17 // NSInvocationOperation *op = [[NSInvocationOperation alloc] initWithTarget:self selector:@selector(testObject) object:nil];
18
19 NSBlockOperation *op = [NSBlockOperation blockOperationWithBlock:^{
20
21 // 讓當前線程睡眠 2.0 秒
22 [NSThread sleepForTimeInterval:2.0f];
23
24 // 打印當前線程
25 NSLog(@"Background - %@", [NSThread currentThread]);
26 }];
27 // 3. 開啟線程
28 [_queue addOperation:op];
29 }
復制代碼
4、GCD多線程技術-Grand Central Dispatch
GCD是基於C語言的框架,該多線程技術是蘋果官方推薦使用的。
1> 要使用GCD,所有的方法都是dispatch開頭的
2> 名詞解釋
global 全局
queue 隊列
async 異步
sync 同步
3> 要執行異步的任務,就在全局隊列中執行即可
dispatch_async 異步執行控制不住先後順序
4> 關於GCD的隊列
全局隊列 dispatch_get_global_queue
參數:優先級 DISPATCH_QUEUE_PRIORITY_DEFAULT
始終是 0
串行隊列 dispatch_queue_create("myQueue", DISPATCH_QUEUE_SERIAL);
是創建得到的,不能直接獲取
主隊列 dispatch_get_main_queue
5> 異步和同步與方法名無關,與運行所在的隊列有關!
提示:要熟悉隊列於同步、異步的運行節奏,一定需要自己編寫代碼測試!
規律:並發隊列(global/concurrent),根據函數名判斷是同步執行(dispatch_sync)還是異步執行(dispatch_async)
串行隊列(serial),無論後面的函數名是同步還是異步,均按照同步執行,並且,如果隊列中第一個函數為同步,則該隊列中所有的函數均在當前線程(一般為主線程)執行