iOS開發之多線程
本文章博主和大家一塊學習多線程,很自然就涉及到線程和進程,然后涵括NSThread、GCD、NSOperation!然后就是最牛叉的RunLoop和Runtime。
一、線程與進程
進程是指在系統中正在運行的一個應用程序,就是一段程序的執行過程,每個進程之間是相互獨立的。一個進程要想執行任務,必須要有線程,至少有一條線程,一個進程的所有任務都是在線程中執行。其實應用程序啟動的時候我么你的系統會默認幫我們的應用程序開啟一條線程,這條線程也叫做“主線程”,或者“UI線程”。
二、多線程
多線程的優點和缺點
- 優點
1.能適當的提高程序的執行效率
2.能適當提高資源利用率(CPU內存利用率) - 缺點
1.開啟線程需要占用一定的內存空間,如果開啟大量的線程,則會占用大量的內存空間,降低程序的性能。
2.線程越多,CUP在調度線程的開銷就越大。
3.程序設計更加復雜,比如線程之間的通信,多線程的數據共享。
多線程的應用
1.使用單利模式時,可以使用GCD
2.耗時操作放入子線程處理,完成后回主線程顯示。
3.從數據庫讀取大量數據,可開辟子線程操作。
4.處理音頻、視頻數據時,在子線程處理。
5.數據同步操作。
三、容易混淆的4個術語
同步和異步主要影響:能不能開啟新的線程。
1.同步:只是在當前線程中執行任務,不具備開啟新線程的能力。
2.異步:可以在新的線程中執行,具備開啟新線程的能力。
并發和串行主要影響:任務的執行方式
并發:多個任務并發(同時)執行。
串行:一個任務執行完畢后,再執行下一個任務。
四、NSThread、NSOperation、GCD
1.NSThread
1)通過NSThread的對象方法(動態創建)
2)通過NSThread的類方法(靜態創建)
NSThread的線程管理
線程創建線程開啟線程取消線程關閉線程暫停設置線程優先級
NSThread的線程通信
指定當前線程執行操作(在其他線程中)指定主線程執行操作在主線程中)指定其他線程執行操作
2.NSOperation
2.1 NSOperation 基本使用
在iOS開發中,為了提升用戶體驗,我們通常會將操作耗時的操作放在主線程之外的線程進行處理。對于正常的簡單操作,我們更多的選擇代碼更少的GCD,讓我們專注于自己的業務邏輯開發。NSOperation在iOS4后也基于GCD實現,但是對于GCD來說可控性更強,并且可以加入操作依賴。
(1) 相關概念
NSOperation是對GCD的封裝,其中有兩個核心概念【隊列+操作】
1.NSOperation本身是抽象類,只能有它的子類。
2.兩大子類分別是:NSBlockOperation、NSInvocationOperation,當然你也可以自定義繼承自NSOperation的類。
(2)基本使用
- 實例化NSOperation的子類,綁定執行的操作。
- 創建NSOperationQueue隊列,將NSOperation實例添加進來。
- 系統會自動將NSOperationQueue隊列中檢測取出和執行NSOperation的操作。
NSInvocationOperation類
// 01 NSInvocationOperation創建線程
/*第一個參數:目標對象第二個參數:該操作要調用的方法,最多接受一個參數第三個參數:調用方法傳遞的參數,如果方法不接受參數,那么該值傳nil*/
- (void) method1 {NSString * imageUrl = @"https://ss1.bdstatic.com/70cFvXSh_Q1YnxGkpoWK1HF6hhy/it/u=482494819,3150422682&fm=200&gp=0.jpg";NSInvocationOperation * invocationOperation = [[NSInvocationOperation alloc] initWithTarget:self selector:@selector(loadImageSource:) object:imageUrl];
// [invocationOperation start];//一旦執行操作,就會調用target的sel方法, 默認情況下調用了start方法后并不會開一條新線程去執行操作,而是在當前線程同步執行操作,只有將NSOperation放到一個NSOperationQueue中,才會異步執行操作NSOperationQueue *queue = [[NSOperationQueue alloc]init];[queue addOperation:invocationOperation];
}
//更新imageView
- (void)updateImage:(NSData *)data{//在主線程中更新UI//將二進制數據轉換為圖片UIImage *image=[UIImage imageWithData:data];//設置imageself.imageView.image=image;
}
NSBlockOperation類
- 創建NSBlockOperation對象
- 通過addExecutionBlock:方法添加更多的操作
隊列的取消、暫停、和恢復
// 恢復隊列,繼續執行
// self.queue.suspended = NO;// 暫停(掛起)隊列,暫停執行
// self.queue.suspended = YES;// 取消隊列的所有操作
[self.queue cancelAllOperations];
操作依賴
NSOperation之間可以設置依賴來保證執行順序
不添加依賴之前op1、op2、op3的順序是隨機的
在不同queue的NSOperation之間創建依賴關系
在不加依賴之前,op1和op2的執行順序是隨機的,添加依賴后op2會在op1之后執行。
線程間的通訊
[[NSOperationQueue mainQueue] addOperationWithBlock:^{[self updateImage:data];}];
3.GCD
3.1基本概念
全稱是Grand Central Dispatch,即:強大的中樞調度器,它是純C語言的,提供了非常多強大的函數。
3.2GCD的優勢:
GCD是蘋果公司為多核的并行運算提出的解決方案
GCD會自動利用更多的CPU內核(比如雙核、四核)
GCD會自動管理線程的生命周期(創建線程、調度任務、銷毀線程)
程序員只需要告訴GCD想要執行什么任務,不需要編寫任何線程管理代碼
3.3GCD的使用步驟:
指定任務:確定想要做的事
將任務添加到隊列中:GCD會自動將隊列中的任務取出,放到對應的線程中執行,任務的取出遵循隊列的FIFO原則:先進先出,后進后出。
3.4GCD的隊列
3.4.1 GCD的隊列可以分為2大類型:
1.并發隊列(Current Dispatch Queue)
2.串行隊列(Serial Dispatch Queue)
3.4.2 使用dispatch_queue_create函數創建隊列
dispatch_queue_create(const char *label, dispatch_queue_attr_t attr);
其中:const char *label 列隊列的名稱dispatch_queue_attr_t attr 隊列的類型
創建一個并發隊列dispatch_queue_t queue1 = dispatch_queue_create("myQueue1", DISPATCH_QUEUE_CONCURRENT);
創建一個串行隊列dispatch_queue_t queue2 = dispatch_queue_create("myQueue2", DISPATCH_QUEUE_SERIAL);
GCD默認意境提供了全局的并發隊列,供整個應用使用,可以無需手動創建
使用dispatch_get_global_queue 函數獲得全局并發隊列//獲得全局的并發隊列dispatch_queue_t queue3 = dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0);其中:第一個參數代表全局并發隊列的優先級#define DISPATCH_QUEUE_PRIORITY_HIGH 2 --》 高#define DISPATCH_QUEUE_PRIORITY_DEFAULT 0 --》 默認(中)#define DISPATCH_QUEUE_PRIORITY_LOW (-2) --》 低#define DISPATCH_QUEUE_PRIORITY_BACKGROUND INT16_MIN --》 后臺第二個參數標記:是為了未來使用保留的!所以這個參數應該永遠指定為0
GCD中獲得串行有2種途徑
1.使用dispatch_queue_create 創建串行隊列,創建串行隊列(隊列類型傳遞NULL或者DISPATCH_QUEUE_SERIAL)dispatch_queue_t queue4 = dispatch_queue_create("com.520.queue", NULL);
2.使用主隊列 (跟主線程相關聯的隊列),主隊列時GCD自帶的一種特殊的串行隊列,放在主隊列中的任務,都會放在主線程中執行,dispatch_get_main_queue()獲得主隊列dispatch_queue_t queue5 = dispatch_get_main_queue();
3.4.3 應用
3.4.3.1 串行隊里
3.4.3.2.并發隊列(Concurrent Dispatch Queue)
#import "ViewController.h"@interface
ViewController ()@end@implementation ViewController
- (void)viewDidLoad
{[super viewDidLoad
];[self example14
];}- (void)example1
{dispatch_queue_t queue
= dispatch_queue_create("queueName", DISPATCH_QUEUE_SERIAL
);dispatch_sync(queue
, ^{NSLog(@
"當前同步任務1一-------%@",[NSThread currentThread
]);sleep(3);});NSLog(@
"1111");dispatch_sync(queue
, ^{NSLog(@
"當前同步任務2一-------%@",[NSThread currentThread
]);sleep(2);});NSLog(@
"2222");dispatch_sync(queue
, ^{NSLog(@
"當前同步任務3一-------%@",[NSThread currentThread
]);sleep(1);});NSLog(@
"走到這里了");
}- (void)example2
{dispatch_queue_t queue
= dispatch_queue_create("queueName", DISPATCH_QUEUE_SERIAL
);dispatch_async(queue
, ^{sleep(5);NSLog(@
"當前異步任務1一-------%@",[NSThread currentThread
]);});NSLog(@
"1111");dispatch_async(queue
, ^{sleep(2);NSLog(@
"當前異步任務2一-------%@",[NSThread currentThread
]);});NSLog(@
"2222");dispatch_async(queue
, ^{sleep(1);NSLog(@
"當前異步任務3一-------%@",[NSThread currentThread
]);});NSLog(@
"走到這里了");
}- (void)example3
{dispatch_queue_t queue
= dispatch_queue_create("queueName", DISPATCH_QUEUE_SERIAL
);dispatch_sync(queue
, ^{sleep(3);NSLog(@
"當前同步任務1一-------%@",[NSThread currentThread
]);});NSLog(@
"1111");dispatch_async(queue
, ^{NSLog(@
"當前異步任務2開始一-------%@",[NSThread currentThread
]);sleep(10);NSLog(@
"當前異步任務2結束一-------%@",[NSThread currentThread
]);});NSLog(@
"2222");dispatch_sync(queue
, ^{sleep(2);NSLog(@
"當前同步任務3一-------%@",[NSThread currentThread
]);});NSLog(@
"3333");dispatch_async(queue
, ^{sleep(1);NSLog(@
"當前異步任務4一-------%@",[NSThread currentThread
]);});NSLog(@
"走到這里了");
}- (void)example4
{dispatch_queue_t queue
= dispatch_queue_create("queueName", DISPATCH_QUEUE_CONCURRENT
);dispatch_sync(queue
, ^{sleep(5);NSLog(@
"當前同步任務1一-------%@",[NSThread currentThread
]);});NSLog(@
"1111");dispatch_sync(queue
, ^{sleep(3);NSLog(@
"當前同步任務2一-------%@",[NSThread currentThread
]);});NSLog(@
"2222");dispatch_sync(queue
, ^{sleep(1);NSLog(@
"當前同步任務3一-------%@",[NSThread currentThread
]);});NSLog(@
"走到這里了");
}- (void)example5
{dispatch_queue_t queue
= dispatch_queue_create("queueName", DISPATCH_QUEUE_CONCURRENT
);dispatch_async(queue
, ^{sleep(5);NSLog(@
"當前同步任務1一-------%@",[NSThread currentThread
]);});NSLog(@
"1111");dispatch_async(queue
, ^{sleep(8);NSLog(@
"當前異步任務2一-------%@",[NSThread currentThread
]);});NSLog(@
"2222");dispatch_async(queue
, ^{sleep(3);NSLog(@
"當前同步任務3一-------%@",[NSThread currentThread
]);});NSLog(@
"3333");dispatch_async(queue
, ^{sleep(1);NSLog(@
"當前異步任務4一-------%@",[NSThread currentThread
]);});NSLog(@
"走到這里了");
}- (void)example6
{dispatch_queue_t queue
= dispatch_queue_create("queueName", DISPATCH_QUEUE_CONCURRENT
);dispatch_sync(queue
, ^{sleep(3);NSLog(@
"當前同步任務1一-------%@",[NSThread currentThread
]);});NSLog(@
"1111");dispatch_async(queue
, ^{sleep(8);NSLog(@
"當前異步任務2一-------%@",[NSThread currentThread
]);});NSLog(@
"2222");dispatch_sync(queue
, ^{sleep(3);NSLog(@
"當前同步任務3一-------%@",[NSThread currentThread
]);});NSLog(@
"3333");dispatch_async(queue
, ^{sleep(1);NSLog(@
"當前異步任務4一-------%@",[NSThread currentThread
]);});NSLog(@
"走到這里了");
}-(void)example71
{dispatch_queue_t queue
= dispatch_queue_create("queue", DISPATCH_QUEUE_SERIAL
);dispatch_sync(queue
, ^{NSLog(@
"任務1...");NSLog(@
"%@", [NSThread currentThread
]);dispatch_sync(queue
, ^{NSLog(@
"任務2...");NSLog(@
"%@", [NSThread currentThread
]);});NSLog(@
"走到這里了");});NSLog(@
"結束");}-(void)example72
{dispatch_queue_t queue
= dispatch_queue_create("queue", DISPATCH_QUEUE_SERIAL
);dispatch_sync(queue
, ^{NSLog(@
"任務1...");NSLog(@
"%@", [NSThread currentThread
]);dispatch_async(queue
, ^{NSLog(@
"任務2...");NSLog(@
"%@", [NSThread currentThread
]);});NSLog(@
"走到這里了");});NSLog(@
"結束");}-(void)example73
{dispatch_queue_t queue
= dispatch_queue_create("queue", DISPATCH_QUEUE_SERIAL
);dispatch_async(queue
, ^{NSLog(@
"任務1...");NSLog(@
"%@", [NSThread currentThread
]);dispatch_sync(queue
, ^{NSLog(@
"任務2...");NSLog(@
"%@", [NSThread currentThread
]);});NSLog(@
"走到這里了");});NSLog(@
"結束");
}-(void)example74
{dispatch_queue_t queue
= dispatch_queue_create("queue", DISPATCH_QUEUE_SERIAL
);dispatch_async(queue
, ^{NSLog(@
"任務1...");NSLog(@
"%@", [NSThread currentThread
]);dispatch_async(queue
, ^{NSLog(@
"任務2...");NSLog(@
"%@", [NSThread currentThread
]);});NSLog(@
"走到這里了");});NSLog(@
"結束");}-(void)example81
{dispatch_queue_t queue
= dispatch_queue_create("queue", DISPATCH_QUEUE_CONCURRENT
);dispatch_sync(queue
, ^{sleep(3);NSLog(@
"任務1...");NSLog(@
"%@", [NSThread currentThread
]);dispatch_sync(queue
, ^{sleep(1);NSLog(@
"任務2...");NSLog(@
"%@", [NSThread currentThread
]);});NSLog(@
"走到這里了");});NSLog(@
"結束");}-(void)example82
{dispatch_queue_t queue
= dispatch_queue_create("queue", DISPATCH_QUEUE_CONCURRENT
);dispatch_sync(queue
, ^{sleep(3);NSLog(@
"任務1...");NSLog(@
"%@", [NSThread currentThread
]);dispatch_async(queue
, ^{sleep(1);NSLog(@
"任務2...");NSLog(@
"%@", [NSThread currentThread
]);NSLog(@
"走到這里了");});});NSLog(@
"結束");
}-(void)example83
{dispatch_queue_t queue
= dispatch_queue_create("queue", DISPATCH_QUEUE_CONCURRENT
);dispatch_async(queue
, ^{sleep(3);NSLog(@
"任務1...");NSLog(@
"%@", [NSThread currentThread
]);dispatch_sync(queue
, ^{sleep(1);NSLog(@
"任務2...");NSLog(@
"%@", [NSThread currentThread
]);});NSLog(@
"走到這里了");});NSLog(@
"結束");
}-(void)example84
{dispatch_queue_t queue
= dispatch_queue_create("queue", DISPATCH_QUEUE_CONCURRENT
);dispatch_async(queue
, ^{sleep(3);NSLog(@
"任務1...");NSLog(@
"%@", [NSThread currentThread
]);dispatch_async(queue
, ^{sleep(1);NSLog(@
"任務2...");NSLog(@
"%@", [NSThread currentThread
]);NSLog(@
"走到這里了");});});NSLog(@
"結束");
}-(void)example91
{dispatch_queue_t queue1
= dispatch_queue_create("queue1", DISPATCH_QUEUE_SERIAL
);dispatch_queue_t queue2
= dispatch_queue_create("queue2", DISPATCH_QUEUE_SERIAL
);dispatch_sync(queue1
, ^{NSLog(@
"%@", [NSThread currentThread
]);NSLog(@
"任務1...");dispatch_sync(queue2
, ^{NSLog(@
"%@", [NSThread currentThread
]);NSLog(@
"任務2...");});NSLog(@
"走到這里了");});NSLog(@
"結束");}-(void)example92
{dispatch_queue_t queue1
= dispatch_queue_create("queue1", DISPATCH_QUEUE_SERIAL
);dispatch_queue_t queue2
= dispatch_queue_create("queue2", DISPATCH_QUEUE_SERIAL
);dispatch_sync(queue1
, ^{NSLog(@
"%@", [NSThread currentThread
]);NSLog(@
"任務1...");dispatch_async(queue2
, ^{NSLog(@
"%@", [NSThread currentThread
]);NSLog(@
"任務2...");});NSLog(@
"走到這里了");});NSLog(@
"結束");}-(void)example10
{dispatch_queue_t queue
= dispatch_queue_create("com.sccc", DISPATCH_QUEUE_SERIAL
);dispatch_group_t group
= dispatch_group_create();dispatch_group_async(group
, queue
, ^{[self doSomething
:^() {NSLog(@
"任務一");}];});dispatch_group_async(group
, queue
, ^{[self doSomething
:^() {NSLog(@
"任務二");}];});dispatch_group_async(group
, queue
, ^{[self doSomething
:^() {NSLog(@
"任務三");}];});dispatch_group_notify(group
, queue
, ^{NSLog(@
"前面的任務已完成");});}-(void)example11
{dispatch_queue_t queue
= dispatch_queue_create("com.sccc", DISPATCH_QUEUE_CONCURRENT
);dispatch_group_t group
= dispatch_group_create();dispatch_group_async(group
, queue
, ^{[self doSomething
:^() {NSLog(@
"任務一");}];});dispatch_group_async(group
, queue
, ^{sleep(3);[self doSomething
:^() {NSLog(@
"任務二");}];});dispatch_group_async(group
, queue
, ^{[self doSomething
:^() {NSLog(@
"任務三");}];});dispatch_group_notify(group
, queue
, ^{NSLog(@
"前面的任務已完成");});}- (void)doSomething
:(void (^)(void))handler
{if (handler
) {sleep(2);handler();}
}-(void)example12
{dispatch_group_t group
= dispatch_group_create();dispatch_queue_t queue
= dispatch_get_global_queue(0, 0);dispatch_group_async(group
, queue
, ^{sleep(5);NSLog(@
"任務一完成");});dispatch_group_async(group
, queue
, ^{sleep(3);NSLog(@
"任務二完成");});dispatch_group_notify(group
, queue
, ^{dispatch_async(dispatch_get_main_queue(), ^{NSLog(@
"完成任務");});});}-(void)example13
{dispatch_group_t group
= dispatch_group_create();dispatch_queue_t queue
= dispatch_get_global_queue(0, 0);dispatch_group_enter(group
);dispatch_async(queue
, ^{sleep(3);NSLog(@
"任務一完成");dispatch_group_leave(group
);});dispatch_group_enter(group
);dispatch_async(queue
, ^{sleep(4);NSLog(@
"任務二完成");dispatch_group_leave(group
);});dispatch_group_notify(group
, queue
, ^{dispatch_async(dispatch_get_main_queue(), ^{NSLog(@
"完成任務");});});}-(void)example14
{dispatch_group_t group
= dispatch_group_create();dispatch_queue_t queue
= dispatch_get_global_queue(0, 0);dispatch_semaphore_t semaphore
= dispatch_semaphore_create(0);dispatch_group_async(group
, queue
, ^{dispatch_async(queue
, ^{sleep(3);NSLog(@
"任務一完成");dispatch_semaphore_signal(semaphore
);});dispatch_semaphore_wait(semaphore
, DISPATCH_TIME_FOREVER
);});dispatch_group_async(group
, queue
, ^{dispatch_async(queue
, ^{sleep(3);NSLog(@
"任務二完成");dispatch_semaphore_signal(semaphore
);});dispatch_semaphore_wait(semaphore
, DISPATCH_TIME_FOREVER
);});dispatch_group_notify(group
, queue
, ^{dispatch_async(dispatch_get_main_queue(), ^{NSLog(@
"完成任務");});});}@end
3.4.3.3.線程間的通信
dispatch_async(dispatch_get_main_queue(), ^{ // 回到主線程,執行UI刷新操作 });
3.4.3.4.其他應用
1.延時執行
iOS常見三種延時執行方式
1)調用NSObject的方法
[self performSelector:@selector(需要執行的方法名) withObject:nil afterDelay:2.0]
2)使用GCD函數
dispatch_after(dispatch_time(DISPATCH_TIME_NOW,(int64_t)(2.0 * NSEC_PER_SEC)), dispatch_get_main_queue(), ^{// 2秒后執行這里的代碼..});
3)使用定時器
[NSTimer scheduledTimerWithTimeInterval:2.0 target:self selector:@selector(需要執行的方法名) userInfo:nil repeats:NO];
2.一次性代碼
static dispatch_once_t onceToken;dispatch_once(&onceToken, ^{//里面的代碼只會被執行一次});
3.隊列組
有這么一個需求,首先:分別異步執行2個耗時的操作,其次:等2個異步操作都執行完畢后,再回到主線程執行操作,如果想要快速高效地實現上述需求,可以考慮用隊列組。
dispatch_group_tgroup = dispatch_group_create(); dispatch_group_async(group,dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^{ // 執行1個耗時的異步操作 }); dispatch_group_async(group,dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^{ // 執行1個耗時的異步操作 }); dispatch_group_notify(group,dispatch_get_main_queue(), ^{ // 等前面的異步操作都執行完畢后,回到主線程... });
4.快速迭代
我只想說速度非常快,要加一個__block因為block代碼默認不能改外面的東西
5.barry執行任務函數
在前面的任務執行結束后它才執行,而且它后面的任務等它執行完成之后才會執行。
下面的例子是在添加到隊列的任務1、任務2、任務3執行完畢后,然后才執行barrier,barrier執行完畢后才執行任務4、任務5。
dispatch_barrier在并發隊列中創建一個同步點,當并發隊列中遇到一個 dispatch_barrier時,會延時執行該 dispatch_barrier,等待在 dispatch_barrier之前提交的任務block執行完后才開始執行,之后,并發隊列繼續執行后續block任務。
6.GCD與定時器
@property (nonatomic,strong) dispatch_source_t timer;
- (void) myTimer {self.timer = dispatch_source_create(DISPATCH_SOURCE_TYPE_TIMER, 0, 0, dispatch_get_main_queue());// 設置定時器的觸發時間(1秒后)和時間間隔(每隔2秒)dispatch_source_set_timer(self.timer, dispatch_time(DISPATCH_TIME_NOW, 1 * NSEC_PER_SEC), 2 * NSEC_PER_SEC, 0);// 設置回調dispatch_source_set_event_handler(self.timer, ^{NSLog(@"Timer %@", [NSThread currentThread]);});// 開始定時器dispatch_resume(self.timer);
}
-(void)viewDidDisappear:(BOOL)animated {dispatch_cancel(self.timer);self.timer = nil;
}
總結
以上是生活随笔為你收集整理的iOS开发之多线程的全部內容,希望文章能夠幫你解決所遇到的問題。
如果覺得生活随笔網站內容還不錯,歡迎將生活随笔推薦給好友。