標籤:
說明:開發技術大同小異,文章寫出來不是為了曬的,只是一個學習記錄過程,有錯誤歡迎指正,喜歡噴人的請滾蛋。
一、實現方案
在iOS中有三種多線程實現技術,它們分別是NSThread、GCD 、NSOperation。
NSThread:基於OC編寫,更加物件導向,可直接操作線程對象,需要程式員手動管理線程生命週期,開發中偶爾使用。
GCD:基於c語言編寫,旨在替代NSThread線程技術,能充分利用裝置的多核,系統自動管理線程生命週期,開發中經常使用。
NSOperation:底層基於GCD封裝的一套OC實現,更加物件導向,系統自動管理線程生命週期,開發中經常使用。
1.NSThread
一個NSthread對象就代表一條線程
相關設定
設定線程的名字
- (void)setName:(NSString *)name;
- (NSString *)name;
獲得當前線程
[NSThread currentThread];
線程調度優先順序:優先順序範圍在0.0~1.0之間,預設是0.5,值越大,優先順序越高,越容易被調度。
- (void)setThreadPriority:(double)priority
- (double)threadPriority
主線程
+ (NSThread *)mainThread; // 獲得主線程
- (BOOL)isMainThread; // 是否為主線程
+ (BOOL)isMainThread; // 是否為主線程
1.線程的建立
1>NSThread *thread = [[NSThread alloc] initWithTarget:self selector:@selector(callback) object:nil];
[thread start];
2>[NSThread detachNewThreadSelector:@selector(callback:) toTarget:self withObject:nil];
3>[self performSelectorInBackground:@selector(callback:) withObject:nil];
第一種相比較後兩種而言可以更加精準的控制線程相關設定,比如線程名稱,優先順序等。
2.線程的狀態
建立:線程建立出來
就緒:調用線程start方法,載入到線程池等待調度
運行:線程得到cpu調度
阻塞:線程睡眠或等待同步鎖
死亡:線程執行完畢或者強制退出或者程式崩潰
3.線程的同步
當多個線程訪問共用資源時,會有資料安全問題,例如寫出錯,讀取髒資料,解決辦法是加互斥鎖。
//加鎖
@synchronized(self){
訪問共用資源代碼
}//解鎖
4.線程的通訊
有時候多個線程之間需要相互連信,互相傳遞資料,比如在子線程下載好圖片資源後需要回到主線程更新UI介面
可以在子線程內部發發非同步請求向主線程傳遞資料。
- (void)threadCommunicate
{
NSThread *thread = [[NSThread alloc] initWithTarget:self selector:@selector(download) object:nil];
[thread setThreadPriority:1];
thread.name = @"線程A";
[thread start];
}
- (void)download
{
//1.下載圖片
NSData *data = [NSData dataWithContentsOfURL:[NSURL URLWithString:@"http://su.bdimg.com/static/superplus/img/logo_white_ee663702.png"]];
UIImage *image = [UIImage imageWithData:data];
//2.更新圖片(子線程下載的圖片返回給主線程更新UI介面)
[self.imageView performSelectorOnMainThread:@selector(setImage:) withObject:image waitUntilDone:NO];
}
2.GCD(Grand Central Dispatch)
GCD會充分利用裝置的多核技術,自動管理線程的生命週期,程式員只需要將任務放在相關隊列中就可以了,不用關心線程的狀態
首先理解兩個概念
隊列:
串列隊列:隊列的任務串列執行
並發隊列:隊列的任務並發執行
請求:
同步:不會開啟新線程
非同步:會開啟新線程,只有放在並發隊列中才會實現多線程技術,放在串列隊列中只會開啟一個線程且任務串列執行。
- (void)viewDidLoad{ [super viewDidLoad]; //1.串列隊列(隊列裡面的操作串列執行) self.serialQueue = dispatch_queue_create("串列對列",DISPATCH_QUEUE_SERIAL); //2.並發隊列(隊列裡面的操作並發執行) self.concurrentQueue = dispatch_queue_create("並行隊列",DISPATCH_QUEUE_CONCURRENT); //3.全域隊列(系統內建並發隊列) self.globalQueue = dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0); //4.主隊列(與主線程相關) self.mainQueue = dispatch_get_main_queue(); NSLog(@"主線程%@",[NSThread currentThread]); //[self gcdCommunicate];}/** * 同步函數dispatch_sync不會開啟新線程 */- (void)sync{ //在串列隊列中同步執行操作 for(int i = 0;i<10;i++){ dispatch_sync(self.serialQueue, ^{ NSLog(@"同步串列%@--%d",[NSThread currentThread],i); }); } //在並發隊列中同步執行操作 for(int i = 0;i<10;i++){ dispatch_sync(self.concurrentQueue, ^{ NSLog(@"同步並發%@",[NSThread currentThread]); }); } //在全域隊列中同步執行操作 for(int i = 0;i<10;i++){ dispatch_sync(self.globalQueue, ^{ NSLog(@"同步全域%@",[NSThread currentThread]); }); } //在主隊列中同步執行操作#warning 在主線程中執行同步操作會卡住 dispatch_sync(self.mainQueue, ^{ NSLog(@"同步主%@",[NSThread currentThread]); });}/** * 非同步函數dispatch_async會開啟新線程 */- (void)async{ //在串列隊列中非同步執行操作(開啟一條子線程,操作串列執行) for(int i = 0;i<10;i++){ dispatch_async(self.serialQueue, ^{ NSLog(@"非同步串列%@---%d",[NSThread currentThread],i); }); } //在並發隊列中非同步執行操作(開啟多條子線程,操作並發執行) for(int i = 0;i<10;i++){ dispatch_async(self.concurrentQueue, ^{ NSLog(@"非同步並發%@---%d",[NSThread currentThread],i); }); } //在全域隊列中非同步執行操作(開啟多條子線程,操作並發執行) for(int i = 0;i<10;i++){ dispatch_async(self.globalQueue, ^{ NSLog(@"非同步全域%@---%d",[NSThread currentThread],i); }); } //在主隊列中非同步執行操作(在主線程上執行,操作串列執行) for(int i = 0;i<10;i++){ dispatch_async(self.globalQueue, ^{ NSLog(@"非同步主%@---%d",[NSThread currentThread],i); }); }}/** * GCD的線程通訊 */- (void)gcdCommunicate{ dispatch_async(self.globalQueue, ^{ NSLog(@"當前線程%@", [NSThread currentThread]); // 下載圖片 NSURL *url = [NSURL URLWithString:@"http://news.baidu.com/z/resource/r/image/2014-06-22/2a1009253cf9fc7c97893a4f0fe3a7b1.jpg"]; NSData *data = [NSData dataWithContentsOfURL:url]; UIImage *image = [UIImage imageWithData:data]; // 回到主線程顯示圖片 dispatch_async(self.mainQueue, ^{ NSLog(@"當前線程%@", [NSThread currentThread]); self.imageView.image = image; }); });}
3.NSOperation
NSOperation底層基於GCD,使用OC編寫,更加物件導向,是蘋果官方比較推薦的技術
配合使用NSOperation和NSOperationQueue也能實現多線程編程
1>使用步驟
首先建立NSOperation對象,將操作封裝到裡面
然後將NSOperation對象添加到NSOperationQueue中
系統會自動將NSOperation中封裝的操作放到一條新線程中執行
2>子類
NSOperation是個抽象類別,並不具備封裝操作的能力,必須使用它的子類
使用NSOperation子類的方式有3種
NSInvocationOperation
NSBlockOperation
自訂子類繼承NSOperation,實現內部相應的方法
/** * NSInvocationOperation的使用 */- (void)invocationOperation{ // 1.建立操作對象, 封裝要執行的操作 NSInvocationOperation *operation = [[NSInvocationOperation alloc] initWithTarget:self selector:@selector(callback) object:nil]; // 2.啟動操作(預設情況下,如果操作沒有放到隊列queue中,都是同步執行) [operation start];}- (void)callback{ NSLog(@"當前線程%@",[NSThread currentThread]);}/** * NSBlockOperation的使用 */- (void)blockOperation{ // 1.建立操作對象, 封裝要執行的操作 NSBlockOperation *operation = [NSBlockOperation blockOperationWithBlock:^{ NSLog(@"當前線程%@--操作1",[NSThread currentThread]); }]; [operation addExecutionBlock:^{ NSLog(@"當前線程%@--操作2",[NSThread currentThread]); }]; [operation addExecutionBlock:^{ NSLog(@"當前線程%@--操作3",[NSThread currentThread]); }]; //監聽操作 operation.completionBlock = ^(){ NSLog(@"當前線程%@--操作完畢", [NSThread currentThread]); }; // 2.啟動操作(如果只有一個操作不會開啟線程,如果有多個操作,就會開啟新線程) [operation start];}/** * NSOperationQueue的使用 */- (void)OperationQueue{ //1.建立操作隊列 NSOperationQueue *queue = [[NSOperationQueue alloc] init]; //設定隊列的最大並發數 queue.maxConcurrentOperationCount = 3; //2.建立操作 NSBlockOperation *operation1 = [NSBlockOperation blockOperationWithBlock:^{ NSLog(@"當前線程%@-操作1",[NSThread currentThread]); }]; NSBlockOperation *operation2 = [NSBlockOperation blockOperationWithBlock:^{ NSLog(@"當前線程%@-操作2",[NSThread currentThread]); }]; NSInvocationOperation *operation3 = [[NSInvocationOperation alloc] initWithTarget:self selector:@selector(invocation) object:nil]; //設定依賴 //[operation2 addDependency:operation1]; //[operation3 addDependency:operation2]; //3.操作放在隊列中 [queue addOperation:operation1]; [queue addOperation:operation2]; [queue addOperation:operation3];}- (void)invocation{ NSLog(@"當前線程%@-操作3",[NSThread currentThread]);}
//寫的有點晚了,本來想寫細點,不過感覺這些代碼和思想都很簡單,方便以後自己重溫就行了,所以寫的糙了點,海涵。
iOS多線程技術