iOS多線程拾貝------操作巨人編程
多線程基本實現方案:pthread - NSThread - GCD - NSOperation Pthread 多平台,可移植c語言,要程式員管理生命週期建立
//這裡已經開啟了多線程,直接在這裡調用子線程想要調用的代碼void * run(void *pramga) {NSLog(@"-------");return NULL;}- (IBAction)btnClick:(id)sender {pthread_t pthread;pthread_create(&pthread, NULL, run, NULL);}
NSThread 物件導向,簡單實用建立
//隱式建立並啟動線程[NSThread detachNewThreadSelector:@selector(threadRun:) toTarget:self withObject:@"etund"];或者//建立線程並且啟動線程[self performSelectorInBackground:@selector(threadRun:) withObject:@"etund"];或者//上述兩個優點是可以快速的建立並啟動線程,方便快捷,但是不能對線程進行多餘屬性的設定,而下面一種方法就可以對線程執行個體屬性的設定,但是要記得要手動開啟線程。NSThread *thread = [[NSThread alloc] initWithTarget:self selector:@selector(threadRun:) object:@"etund"];[thread start];
GCD聽說全稱是叫“牛逼的中樞調度器”,但是我還是喜歡叫大中央調度純C語言,有很多強大的函數優勢:(純屬板書)GCD是蘋果公司為多核的並行運算提出的解決方案GCD會自動利用更多的CPU核心(比如雙核、四核)GCD會自動管理線程的生命週期(建立線程、調度任務、銷毀線程)程式員只需要告訴GCD想要執行什麼任務,不需要編寫任何線程管理代碼核心:清楚什麼是任務,隊列串列與並行不能決定是否要開啟新縣城並行表明具有建立新線程的能力,但不一定建立新線程常用GCD內容 串列同步(並行同步/全域隊列同步),由於串列同步,並行同步,以及全域隊列同步都是不建立線程按順序執行,所以歸為一類來講。(不開任何子線程,在主線程中執行)
//串列dispatch_queue_t queue = dispatch_queue_create("etund", DISPATCH_QUEUE_SERIAL);//並行//dispatch_queue_t queue = dispatch_queue_create("etund", DISPATCH_QUEUE_CONCURRENT);dispatch_sync(queue, ^{ NSLog(@"%@---1",[NSThread currentThread]);});dispatch_sync(queue, ^{ NSLog(@"%@----2",[NSThread currentThread]);});dispatch_sync(queue, ^{ NSLog(@"%@----3",[NSThread currentThread]);});運行結果2015-07-08 19:09:39.611 Pthread-多平台[63090:302902] <NSThread: 0x7fc79142c1d0>{number = 1, name = main}---12015-07-08 19:09:39.612 Pthread-多平台[63090:302902] <NSThread: 0x7fc79142c1d0>{number = 1, name = main}----22015-07-08 19:09:39.612 Pthread-多平台[63090:302902] <NSThread: 0x7fc79142c1d0>{number = 1, name = main}----3
串列非同步 (開啟一個子線程,在子線程中執行)
dispatch_queue_t queue = dispatch_queue_create("etund", DISPATCH_QUEUE_SERIAL);dispatch_async(queue, ^{ NSLog(@"%@---1",[NSThread currentThread]);});dispatch_async(queue, ^{ NSLog(@"%@---2",[NSThread currentThread]);});dispatch_async(queue, ^{ NSLog(@"%@---3",[NSThread currentThread]);});/*運行結果2015-07-08 19:25:37.811 Pthread-多平台[68041:316565] <NSThread: 0x7fb35850fe30>{number = 3, name = (null)}---12015-07-08 19:25:37.811 Pthread-多平台[68041:316565] <NSThread: 0x7fb35850fe30>{number = 3, name = (null)}---22015-07-08 19:25:37.811 Pthread-多平台[68041:316565] <NSThread: 0x7fb35850fe30>{number = 3, name = (null)}---3*/
並行非同步(全域隊列非同步)雖然線程的執行順序不一樣,但是任務從隊列裡面拿出來放進線程的順序是按照先進先出的這是根本,基礎。(有幾個任務,開啟幾個子線程,在各自的子線程中執行)
dispatch_queue_t queue = dispatch_queue_create("etund", DISPATCH_QUEUE_CONCURRENT);dispatch_async(queue, ^{ NSLog(@"%@---1",[NSThread currentThread]);});dispatch_async(queue, ^{ NSLog(@"%@---2",[NSThread currentThread]);});dispatch_async(queue, ^{ NSLog(@"%@---3",[NSThread currentThread]);});// 雖然線程的執行順序不一樣,但是任務從隊列裡面拿出來放進線程的順序是按照先進先出/**2015-07-08 19:27:46.060 Pthread-多平台[68694:318231] <NSThread: 0x7f9a89c126b0>{number = 4, name = (null)}---22015-07-08 19:27:46.060 Pthread-多平台[68694:318230] <NSThread: 0x7f9a8c211400>{number = 5, name = (null)}---32015-07-08 19:27:46.060 Pthread-多平台[68694:318171] <NSThread: 0x7f9a89f9efe0>{number = 3, name = (null)}---1*/
主隊列非同步,不開任何子線程,在主線程中運行,也對應了那句話,非同步隊列只是具有開啟子線程的能力,但是不一定開子線程。
// 主隊列非同步(不開線程)dispatch_async(dispatch_get_main_queue(), ^{ NSLog(@"%@---1",[NSThread currentThread]);});dispatch_async(dispatch_get_main_queue(), ^{ NSLog(@"%@---2",[NSThread currentThread]);});dispatch_async(dispatch_get_main_queue(), ^{ NSLog(@"%@---3",[NSThread currentThread]); ;});/*2015-07-08 19:34:25.440 Pthread-多平台[70710:322816] <NSThread: 0x7fe0d1418200>{number = 1, name = main}---12015-07-08 19:34:25.440 Pthread-多平台[70710:322816] <NSThread: 0x7fe0d1418200>{number = 1, name = main}---22015-07-08 19:34:25.440 Pthread-多平台[70710:322816] <NSThread: 0x7fe0d1418200>{number = 1, name = main}---3*/
主隊列同步
- (void)gcdTest_2_4{ NSLog(@"=-=-=-"); // 主隊列同步(阻塞) dispatch_sync(dispatch_get_main_queue(), ^{ NSLog(@"%@---1",[NSThread currentThread]); }); dispatch_sync(dispatch_get_main_queue(), ^{ NSLog(@"%@---2",[NSThread currentThread]); }); dispatch_sync(dispatch_get_main_queue(), ^{ NSLog(@"%@---3",[NSThread currentThread]); }); NSLog(@"=-=-=-");}
------------至此,基本GCD隊列已經被差不多就這樣了,下面來一下有趣的用法 GCD隊列組,有這麼一個需求,你的一個步驟要在其他步驟完成之後才能完成,也就是後續步驟要依賴於前期步驟,這是GCD隊列組以及Barrier隊列(柵欄隊列)不失為一個好辦法,
//GCD隊列組方式 // (線程組)(線程通訊)// dispatch_queue_t queue = dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0); dispatch_queue_t queue = dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0); dispatch_group_t group = dispatch_group_create(); // 載入圖片1 dispatch_group_async(group, queue, ^{ NSURL *url = [NSURL URLWithString:@"http://f.hiphotos.baidu.com/image/pic/item/d788d43f8794a4c2e882eb8b0df41bd5ac6e39e8.jpg"]; NSData *data = [NSData dataWithContentsOfURL:url]; self.image1 = [UIImage imageWithData:data]; }); // 載入圖片2 dispatch_group_async(group, queue, ^{ NSURL *url = [NSURL URLWithString:@"http://h.hiphotos.baidu.com/image/pic/item/ac6eddc451da81cbd668501c5666d01608243151.jpg"]; NSData *data = [NSData dataWithContentsOfURL:url]; self.image2 = [UIImage imageWithData:data]; }); // 合并 dispatch_group_notify(group, queue, ^{ UIGraphicsBeginImageContextWithOptions(CGSizeMake(100, 100), NO, 0); [self.image1 drawAsPatternInRect:CGRectMake(0, 0, 50, 100)]; [self.image2 drawAsPatternInRect:CGRectMake(50, 0, 50, 100)]; UIImage *image = UIGraphicsGetImageFromCurrentImageContext(); UIGraphicsEndImageContext(); //GCD線程之間的通訊 dispatch_async(dispatch_get_main_queue(), ^{ self.myView.image = image; }); });//柵欄dispatch_barrier方式 dispatch_queue_t queue = dispatch_queue_create("etund", DISPATCH_QUEUE_CONCURRENT);//建立多個線程 dispatch_async(queue, ^{ NSURL *url = [NSURL URLWithString:@"http://f.hiphotos.baidu.com/image/pic/item/d788d43f8794a4c2e882eb8b0df41bd5ac6e39e8.jpg"]; NSData *data = [NSData dataWithContentsOfURL:url]; self.image1 = [UIImage imageWithData:data]; }); dispatch_async(queue, ^{ NSURL *url = [NSURL URLWithString:@"http://h.hiphotos.baidu.com/image/pic/item/ac6eddc451da81cbd668501c5666d01608243151.jpg"]; NSData *data = [NSData dataWithContentsOfURL:url]; self.image2 = [UIImage imageWithData:data]; }); dispatch_barrier_async(queue, ^{ }); dispatch_async(queue, ^{ UIGraphicsBeginImageContextWithOptions(CGSizeMake(100, 100), NO, 0); [self.image1 drawAsPatternInRect:CGRectMake(0, 0, 50, 100)]; [self.image2 drawAsPatternInRect:CGRectMake(50, 0, 50, 100)]; UIImage *image = UIGraphicsGetImageFromCurrentImageContext(); UIGraphicsEndImageContext(); dispatch_async(dispatch_get_main_queue(), ^{ self.myView.image = image; }); });
消極式載入 dispatch_after(dispatch_time(DISPATCH_TIME_NOW, (int64_t)(2.0 * NSEC_PER_SEC)), dispatch_get_main_queue(), ^{ // 2秒後非同步執行這裡的代碼...}); 快速迭代,當我們不需要注重迭代的順序,只需要快速獲得子項目的時候,GCD的快速迭代為你提供了途徑
// (快速迭代) dispatch_queue_t queue = dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0); dispatch_apply(self.view.subviews.count, queue, ^(size_t index) { id obj = self.view.subviews[index]; NSLog(@"---%zu---%@",index,obj); }); /* 2015-07-08 22:26:39.851 Pthread-多平台[972:17366] ---0---<_UILayoutGuide: 0x7fd86b644e00; frame = (0 0; 0 20); hidden = YES; layer = <CALayer: 0x7fd86b643ab0>> 2015-07-08 22:26:39.851 Pthread-多平台[972:17444] ---2---<UIImageView: 0x7fd86b645ba0; frame = (100 100; 100 100); clipsToBounds = YES; userInteractionEnabled = NO; layer = <CALayer: 0x7fd86b643290>> 2015-07-08 22:26:39.851 Pthread-多平台[972:17435] ---1---<_UILayoutGuide: 0x7fd86b6457b0; frame = (0 568; 0 0); hidden = YES; layer = <CALayer: 0x7fd86b644040>> */
once一次性代碼(單例模式設計),有時候我們需要用到單例模式做一些操作例如:傳值時,就會用到單例設計模式,設計單例模式的方法很多,其中最重要的是要做到安全執行緒,而GCD就提供了這麼一個結構體來保證在建立單例過程中的安全執行緒
ETPerson.h+ (instancetype)sharePerson;ETPerson.m@implementation ETPersonstatic ETPerson *_person;+ (instancetype)sharePerson{ static dispatch_once_t onceDispatch; dispatch_once(&onceDispatch, ^{ _person = [[ETPerson alloc] init]; }); return _person;}+ (instancetype)allocWithZone:(struct _NSZone *)zone{ static dispatch_once_t onceDispatch; dispatch_once(&onceDispatch, ^{ _person = [super allocWithZone:zone]; }); return _person;}- (id)copyWithZone:(NSZone *)zone{ return _person;}@end調用// onece(單例) NSLog(@"%@----%@------%@-------%@------%@-----%@",[[ETPerson alloc] init],[[ETPerson alloc] init],[ETPerson copy],[ETPerson copy],[ETPerson sharePerson],[ETPerson sharePerson]); /*運行結果 2015-07-08 23:26:57.292 Pthread-多平台[1350:37528] <ETPerson: 0x7fc4bb4041c0>----<ETPerson: 0x7fc4bb4041c0>------ETPerson-------ETPerson------<ETPerson: 0x7fc4bb4041c0>-----<ETPerson: 0x7fc4bb4041c0> */
線程通訊線程之間的通訊,線程的通訊,在一個進程中,線程往往不是鼓勵存在的,多個線程之間需要經常進行通訊線程間通訊的體現在一個線程傳遞資料給另外一個線程在一個線程中執行完成任務後,轉到另一個線程繼續執行任務NSThread的線程通訊
//這個方法是指在當前線程運行完後調到主線程裡面運行 - (void)performSelectorOnMainThread:(SEL)aSelector withObject:(id)arg waitUntilDone:(BOOL)wait;//這個方法是指在當前線程運行完後調用另外一個線程裡面運行 - (void)performSelector:(SEL)aSelector onThread:(NSThread *)thr withObject:(id)arg waitUntilDone:(BOOL)wait
GCD的線程通訊,GCD的線程通訊十分簡單,只是在代碼塊裡面調用代碼塊,直接上代碼吧。
從子線程回到主線程dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^{ // 執行耗時的非同步作業... dispatch_async(dispatch_get_main_queue(), ^{ // 回到主線程,執行UI重新整理操作 });});
至此,iOS裡面簡單的多線程GCD以及NSThread以及PThread部分就入門了,明天更新NSOPeration。