IOS-网络(GCD)
?
-(void)testFun{static dispatch_once_t oneTocken;dispatch_once(&oneTocken, ^{//這就相當于一門衛,多個線程爭相要來執行這代碼塊,門衛說:只能有一個人進去,你們在這里等著,進去的人出來了,門衛又說:你們別進去來,直接走吧,就跟著剛才出來的線程走了,(以后再有線程來執行這個方法都不讓其執行,一次應用程序周期里只執行一次)[NSThread sleepForTimeInterval:4];NSLog(@"執行一次oncetoken:%@,,%i",currentThread,isMainthread);});NSLog(@"%@",currentThread); }?
double delayInSeconds = 2.0;dispatch_time_t poptime=dispatch_time(DISPATCH_TIME_NOW, delayInSeconds*NSEC_PER_SEC);dispatch_after(poptime, dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_HIGH, 0), ^{NSLog(@"%@",currentThread);});//異步延遲執行dispatch_after又開啟線程的能力所以是個異步?轉摘http://www.cnblogs.com/wendingding/p/3806821.html
iOS開發多線程篇—GCD介紹
一、簡單介紹
1.什么是GCD?
全稱是Grand Central Dispatch,可譯為“牛逼的中樞調度器”
純C語言,提供了非常多強大的函數
?
2.GCD的優勢
GCD是蘋果公司為多核的并行運算提出的解決方案
GCD會自動利用更多的CPU內核(比如雙核、四核)
GCD會自動管理線程的生命周期(創建線程、調度任務、銷毀線程)
程序員只需要告訴GCD想要執行什么任務,不需要編寫任何線程管理代碼
?
3.提示
(1)GCD存在于libdispatch.dylib這個庫中,這個調度庫包含了GCD的所有的東西,但任何IOS程序,默認就加載了這個庫,在程序運行的過程中會動態的加載這個庫,不需要我們手動導入。 點擊+a按鈕,可以導入框架。 (2)GCD是純C語言的,因此我們在編寫GCD相關代碼的時候,面對的函數,而不是方法。 (3)GCD中的函數大多數都以dispatch開頭。二、任務和隊列
GCD中有2個核心概念
(1)任務:執行什么操作
(2)隊列:用來存放任務
?
GCD的使用就2個步驟
(1)定制任務
(2)確定想做的事情
?
將任務添加到隊列中,GCD會自動將隊列中的任務取出,放到對應的線程中執行
提示:任務的取出遵循隊列的FIFO原則:先進先出,后進后出
?
三、執行任務
1.GCD中有2個用來執行任務的函數
說明:把右邊的參數(任務)提交給左邊的參數(隊列)進行執行。
(1)用同步的方式執行任務?dispatch_sync(dispatch_queue_t queue, dispatch_block_t block);
參數說明:
queue:隊列
block:任務
?
(2)用異步的方式執行任務?dispatch_async(dispatch_queue_t queue, dispatch_block_t block);
2.同步和異步的區別
同步:在當前線程中執行
異步:在另一條線程中執行
?
四、隊列
1.隊列的類型
GCD的隊列可以分為2大類型
(1)并發隊列(Concurrent Dispatch Queue)
可以讓多個任務并發(同時)執行(自動開啟多個線程同時執行任務)并發功能只有在異步(dispatch_async)函數下才有效
(2)串行隊列(Serial Dispatch Queue)
讓任務一個接著一個地執行(一個任務執行完畢后,再執行下一個任務)
2.補充說明
有4個術語比較容易混淆:同步、異步、并發、串行
同步和異步決定了要不要開啟新的線程
同步:在當前線程中執行任務,不具備開啟新線程的能力
異步:在新的線程中執行任務,具備開啟新線程的能力
?
并發和串行決定了任務的執行方式
并發:多個任務并發(同時)執行
串行:一個任務執行完畢后,再執行下一個任務
?
3.串行隊列
GCD中獲得串行有2種途徑
(1)使用dispatch_queue_create函數創建串行隊列
dispatch_queue_t ?dispatch_queue_create(const char *label, ?dispatch_queue_attr_t attr); //?隊列名稱, 隊列屬性,一般用NULL即可
示例:
dispatch_queue_t queue = dispatch_queue_create("wendingding", NULL); // 創建
dispatch_release(queue); // 非ARC需要釋放手動創建的隊列
?
(2)使用主隊列(跟主線程相關聯的隊列)
主隊列是GCD自帶的一種特殊的串行隊列,放在主隊列中的任務,都會放到主線程中執行
使用dispatch_get_main_queue()獲得主隊列
示例:
dispatch_queue_t queue = dispatch_get_main_queue();
?
4.并發隊列
GCD默認已經提供了全局的并發隊列,供整個應用使用,不需要手動創建
使用dispatch_get_global_queue函數獲得全局的并發隊列
dispatch_queue_t dispatch_get_global_queue(dispatch_queue_priority_t priority,unsigned long flags); // 此參數暫時無用,用0即可
示例:
這個參數是留給以后用的,暫時用不上,傳個0。 第一個參數為優先級,這里選擇默認的。獲取一個全局的默認優先級的并發隊列。dispatch_queue_t queue = 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 // 后臺
5.各種隊列的執行效果
?
五、代碼示例
(1)用異步函數往并發隊列中添加任務
?
1 //2 // YYViewController.m3 // 08-GCD基本使用4 //5 // Created by apple on 14-6-24.6 // Copyright (c) 2014年 itcase. All rights reserved.7 //8 9 #import "YYViewController.h" 10 11 @interface YYViewController () 12 13 @end 14 15 @implementation YYViewController 16 17 - (void)viewDidLoad 18 { 19 [super viewDidLoad]; 20 //1.獲得全局的并發隊列 21 dispatch_queue_t queue = dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0); 22 //2.添加任務到隊列中,就可以執行任務 23 //異步函數:具備開啟新線程的能力 24 dispatch_async(queue, ^{ 25 NSLog(@"下載圖片1----%@",[NSThread currentThread]); 26 }); 27 dispatch_async(queue, ^{ 28 NSLog(@"下載圖片2----%@",[NSThread currentThread]); 29 }); 30 dispatch_async(queue, ^{ 31 NSLog(@"下載圖片2----%@",[NSThread currentThread]); 32 }); 33 //打印主線程 34 NSLog(@"主線程----%@",[NSThread mainThread]); 35 36 } 37 38 @end總結:同時開啟三個子線程
(2)用異步函數往串行隊列中添加任務
1 //2 // YYViewController.m3 // 09—GCD基本使用24 //5 // Created by apple on 14-6-24.6 // Copyright (c) 2014年 itcase. All rights reserved.7 //8 9 #import "YYViewController.h" 10 11 @interface YYViewController () 12 13 @end 14 15 @implementation YYViewController 16 17 - (void)viewDidLoad 18 { 19 [super viewDidLoad]; 20 21 //打印主線程 22 NSLog(@"主線程----%@",[NSThread mainThread]); 23 24 //創建串行隊列 25 dispatch_queue_t queue= dispatch_queue_create("wendingding", NULL); 26 //第一個參數為串行隊列的名稱,是c語言的字符串 27 //第二個參數為隊列的屬性,一般來說串行隊列不需要賦值任何屬性,所以通常傳空值(NULL) 28 29 //2.添加任務到隊列中執行 30 dispatch_async(queue, ^{ 31 NSLog(@"下載圖片1----%@",[NSThread currentThread]); 32 }); 33 dispatch_async(queue, ^{ 34 NSLog(@"下載圖片2----%@",[NSThread currentThread]); 35 }); 36 dispatch_async(queue, ^{ 37 NSLog(@"下載圖片2----%@",[NSThread currentThread]); 38 }); 39 40 //3.釋放資源 41 // dispatch_release(queue); 42 } 43 44 @end總結:會開啟線程,但是只開啟一個線程
(3)用同步函數往并發隊列中添加任務
1 //2 // YYViewController.m3 // 10-CGD基本使用34 //5 // Created by apple on 14-6-24.6 // Copyright (c) 2014年 itcase. All rights reserved.7 //8 9 #import "YYViewController.h" 10 11 @interface YYViewController () 12 13 @end 14 15 @implementation YYViewController 16 /** 17 * 用同步函數往并發隊列中添加任務 18 */ 19 - (void)viewDidLoad 20 { 21 [super viewDidLoad]; 22 23 //打印主線程 24 NSLog(@"主線程----%@",[NSThread mainThread]); 25 26 //創建串行隊列 27 dispatch_queue_t queue= dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0); 28 29 30 //2.添加任務到隊列中執行 31 dispatch_sync(queue, ^{ 32 NSLog(@"下載圖片1----%@",[NSThread currentThread]); 33 }); 34 dispatch_sync(queue, ^{ 35 NSLog(@"下載圖片2----%@",[NSThread currentThread]); 36 }); 37 dispatch_sync(queue, ^{ 38 NSLog(@"下載圖片3----%@",[NSThread currentThread]); 39 }); 40 } 41 42 @end總結:不會開啟新的線程,并發隊列失去了并發的功能
(4)用同步函數往串行隊列中添加任務
1 //2 // YYViewController.m3 // 11—CGD基本使用44 //5 // Created by apple on 14-6-24.6 // Copyright (c) 2014年 itcase. All rights reserved.7 //8 9 #import "YYViewController.h" 10 11 @interface YYViewController () 12 13 @end 14 15 @implementation YYViewController 16 17 18 /** 19 *用同步函數往串行隊列中添加任務 20 */ 21 - (void)viewDidLoad 22 { 23 [super viewDidLoad]; 24 NSLog(@"用同步函數往串行隊列中添加任務"); 25 //打印主線程 26 NSLog(@"主線程----%@",[NSThread mainThread]); 27 28 //創建串行隊列 29 dispatch_queue_t queue= dispatch_queue_create("wendingding", NULL); 30 31 //2.添加任務到隊列中執行 32 dispatch_sync(queue, ^{ 33 NSLog(@"下載圖片1----%@",[NSThread currentThread]); 34 }); 35 dispatch_sync(queue, ^{ 36 NSLog(@"下載圖片2----%@",[NSThread currentThread]); 37 }); 38 dispatch_sync(queue, ^{ 39 NSLog(@"下載圖片3----%@",[NSThread currentThread]); 40 }); 41 } 42 43 @end總結:不會開啟新的線程
(5)補充
補充:隊列名稱的作用:
將來調試的時候,可以看得出任務是在哪個隊列中執行的。
(6)小結
說明:同步函數不具備開啟線程的能力,無論是什么隊列都不會開啟線程;異步函數具備開啟線程的能力,開啟幾條線程由隊列決定(串行隊列只會開啟一條新的線程,并發隊列會開啟多條線程)。
同步函數
(1)并發隊列:不會開線程
(2)串行隊列:不會開線程
異步函數
(1)并發隊列:能開啟N條線程
(2)串行隊列:開啟1條線程
補充:
凡是函數中,各種函數名中帶有create\copy\new\retain等字眼,都需要在不需要使用這個數據的時候進行release。 GCD的數據類型在ARC的環境下不需要再做release。 CF(core Foundation)的數據類型在ARC環境下還是需要做release。? 異步函數具備開線程的能力,但不一定會開線程 轉摘http://www.cnblogs.com/wendingding/p/3807265.htmliOS開發多線程篇—GCD的基本使用
一、主隊列介紹
主隊列:是和主線程相關聯的隊列,主隊列是GCD自帶的一種特殊的串行隊列,放在主隊列中得任務,都會放到主線程中執行。 提示:如果把任務放到主隊列中進行處理,那么不論處理函數是異步的還是同步的都不會開啟新的線程。 獲取主隊列的方式:?dispatch_queue_t?queue=dispatch_get_main_queue();
(1)使用異步函數執行主隊列中得任務,代碼示例:
1 //2 // YYViewController.m3 // 12-GCD的基本使用(主隊列)4 //5 // Created by 孔醫己 on 14-6-25.6 // Copyright (c) 2014年 itcast. All rights reserved.7 //8 9 #import "YYViewController.h" 10 11 @interface YYViewController () 12 13 @end 14 15 @implementation YYViewController 16 17 - (void)viewDidLoad 18 { 19 [super viewDidLoad]; 20 21 //打印主線程 22 NSLog(@"打印主線程--%@", [NSThread mainThread]); 23 24 //1.獲取主隊列 25 dispatch_queue_t queue=dispatch_get_main_queue(); 26 //2.把任務添加到主隊列中執行 27 dispatch_async(queue, ^{ 28 NSLog(@"使用異步函數執行主隊列中的任務1--%@",[NSThread currentThread]); 29 }); 30 dispatch_async(queue, ^{ 31 NSLog(@"使用異步函數執行主隊列中的任務2--%@",[NSThread currentThread]); 32 }); 33 dispatch_async(queue, ^{ 34 NSLog(@"使用異步函數執行主隊列中的任務3--%@",[NSThread currentThread]); 35 }); 36 } 37 38 @end執行效果:
?(2)使用同步函數,在主線程中執行主隊列中得任務,會發生死循環,任務無法往下執行。示意圖如下:
二、基本使用
1.問題 ?
任務1和任務2是在主線程執行還是子線程執行,還是單獨再開啟一個新的線程?
1 //2 // YYViewController.m3 // 13-GCD基本使用(問題)4 //5 // Created by 孔醫己 on 14-6-25.6 // Copyright (c) 2014年 itcast. All rights reserved.7 //8 9 #import "YYViewController.h" 10 11 @interface YYViewController () 12 13 @end 14 15 @implementation YYViewController 16 17 - (void)viewDidLoad 18 { 19 [super viewDidLoad]; 20 //開啟一個后臺線程,調用執行test方法 21 [self performSelectorInBackground:@selector(test) withObject:nil]; 22 } 23 24 -(void)test 25 { 26 NSLog(@"當前線程---%@",[NSThread currentThread]); 27 dispatch_queue_t queue = dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0); 28 29 //異步函數 30 dispatch_async(queue, ^{ 31 NSLog(@"任務1所在的線程----%@",[NSThread currentThread]); 32 }); 33 34 //同步函數 35 dispatch_sync(queue, ^{ 36 NSLog(@"任務2所在的線程----%@",[NSThread currentThread]); 37 }); 38 } 39 40 @end打印結果:
2.開啟子線程,加載圖片
1 //2 // YYViewController.m3 // 14-GCD基本使用(下載圖片)4 //5 // Created by 孔醫己 on 14-6-25.6 // Copyright (c) 2014年 itcast. All rights reserved.7 //8 9 #import "YYViewController.h" 10 11 @interface YYViewController () 12 @property (weak, nonatomic) IBOutlet UIImageView *imageView; 13 14 @end 15 16 @implementation YYViewController 17 18 - (void)viewDidLoad 19 { 20 [super viewDidLoad]; 21 22 } 23 24 //當手指觸摸屏幕的時候,從網絡上下載一張圖片到控制器的view上顯示 25 -(void)touchesBegan:(NSSet *)touches withEvent:(UIEvent *)event 26 { 27 28 //1.獲取一個全局串行隊列 29 dispatch_queue_t queue = dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0); 30 //2.把任務添加到隊列中執行 31 dispatch_async(queue, ^{ 32 33 //打印當前線程 34 NSLog(@"%@",[NSThread currentThread]); 35 //3.從網絡上下載圖片 36 NSURL *urlstr=[NSURL URLWithString:@"http://h.hiphotos.baidu.com/baike/w%3D268/sign=30b3fb747b310a55c424d9f28f444387/1e30e924b899a9018b8d3ab11f950a7b0308f5f9.jpg"]; 37 NSData *data=[NSData dataWithContentsOfURL:urlstr]; 38 UIImage *image=[UIImage imageWithData:data]; 39 //提示 40 NSLog(@"圖片加載完畢"); 41 42 //4.回到主線程,展示圖片 43 [self.imageView performSelectorOnMainThread:@selector(setImage:) withObject:image waitUntilDone:NO]; 44 }); 45 } 46 47 @end顯示效果:
打印結果:
要求使用GCD的方式,在子線程加載圖片完畢后,主線程拿到加載的image刷新UI界面。
1 //2 // YYViewController.m3 // 14-GCD基本使用(下載圖片)4 //5 // Created by 孔醫己 on 14-6-25.6 // Copyright (c) 2014年 itcast. All rights reserved.7 //8 9 #import "YYViewController.h" 10 11 @interface YYViewController () 12 @property (weak, nonatomic) IBOutlet UIImageView *imageView; 13 14 @end 15 16 @implementation YYViewController 17 18 - (void)viewDidLoad 19 { 20 [super viewDidLoad]; 21 22 } 23 24 //當手指觸摸屏幕的時候,從網絡上下載一張圖片到控制器的view上顯示 25 -(void)touchesBegan:(NSSet *)touches withEvent:(UIEvent *)event 26 { 27 28 //1.獲取一個全局串行隊列 29 dispatch_queue_t queue = dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0); 30 //2.把任務添加到隊列中執行 31 dispatch_async(queue, ^{ 32 33 //打印當前線程 34 NSLog(@"%@",[NSThread currentThread]); 35 //3.從網絡上下載圖片 36 NSURL *urlstr=[NSURL URLWithString:@"http://h.hiphotos.baidu.com/baike/w%3D268/sign=30b3fb747b310a55c424d9f28f444387/1e30e924b899a9018b8d3ab11f950a7b0308f5f9.jpg"]; 37 NSData *data=[NSData dataWithContentsOfURL:urlstr]; 38 UIImage *image=[UIImage imageWithData:data]; 39 //提示 40 NSLog(@"圖片加載完畢"); 41 42 //4.回到主線程,展示圖片 43 // [self.imageView performSelectorOnMainThread:@selector(setImage:) withObject:image waitUntilDone:NO]; 44 dispatch_async(dispatch_get_main_queue(), ^{ 45 self.imageView.image=image; 46 //打印當前線程 47 NSLog(@"%@",[NSThread currentThread]); 48 }); 49 }); 50 } 51 52 @end打印結果:
好處:子線程中得所有數據都可以直接拿到主線程中使用,更加的方便和直觀。
?
三、線程間通信
從子線程回到主線程
dispatch_async( dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^{ // 執?耗時的異步操作... dispatch_async(dispatch_get_main_queue(), ^{// 回到主線程,執?UI刷新操作 }); }); ??
轉摘http://www.cnblogs.com/wendingding/p/3807716.html
iOS開發多線程篇—GCD的常見用法
一、延遲執行 1.介紹 iOS常見的延時執行有2種方式(1)調用NSObject的方法
[self?performSelector:@selector(run)?withObject:nil?afterDelay:2.0];
// 2秒后再調用self的run方法
?
(2)使用GCD函數
dispatch_after(dispatch_time(DISPATCH_TIME_NOW, (int64_t)(2.0?*?NSEC_PER_SEC)),?dispatch_get_main_queue(), ^{
? ??// 2秒后異步執行這里的代碼...
});
2.說明
第一種方法,該方法在那個線程調用,那么run就在哪個線程執行(當前線程),通常是主線程。[self?performSelector:@selector(run)?withObject:nil?afterDelay:3.0];
說明:在3秒鐘之后,執行run函數
代碼示例:
1 //2 // YYViewController.m3 // 01-GCD的常見使用(延遲執行)4 //5 // Created by apple on 14-6-25.6 // Copyright (c) 2014年 itcase. All rights reserved.7 //8 9 #import "YYViewController.h" 10 11 @interface YYViewController () 12 13 @end 14 15 @implementation YYViewController 16 17 - (void)viewDidLoad 18 { 19 [super viewDidLoad]; 20 NSLog(@"打印線程----%@",[NSThread currentThread]); 21 //延遲執行 22 //第一種方法:延遲3秒鐘調用run函數 23 [self performSelector:@selector(run) withObject:nil afterDelay:2.0]; 24 25 } 26 -(void)run 27 { 28 NSLog(@"延遲執行----%@",[NSThread currentThread]); 29 } 30 31 -(void)touchesBegan:(NSSet *)touches withEvent:(UIEvent *)event 32 { 33 //在異步函數中執行 34 dispatch_queue_t queue = dispatch_queue_create("wendingding", 0); 35 36 dispatch_sync(queue, ^{ 37 [self performSelector:@selector(test) withObject:nil afterDelay:1.0]; 38 }); 39 NSLog(@"異步函數"); 40 } 41 -(void)test 42 { 43 NSLog(@"異步函數中延遲執行----%@",[NSThread currentThread]); 44 } 45 @end說明:如果把該方法放在異步函數中執行,則方法不會被調用(BUG?)
第二種方法,?dispatch_after(dispatch_time(DISPATCH_TIME_NOW, (int64_t)(5.0?*?NSEC_PER_SEC)),?dispatch_get_main_queue(), ^{
? ? ? ?//延遲執行的方法
? ? });
說明:在5秒鐘之后,執行block中的代碼段。
參數說明:
什么時間,執行這個隊列中的這個任務。
代碼示例:
1 //2 // YYViewController.m3 // 02-GCD常見使用(延遲執行2)4 //5 // Created by apple on 14-6-25.6 // Copyright (c) 2014年 itcase. All rights reserved.7 //8 9 #import "YYViewController.h" 10 11 @interface YYViewController () 12 13 @end 14 15 @implementation YYViewController 16 17 - (void)viewDidLoad 18 { 19 [super viewDidLoad]; 20 21 NSLog(@"打印當前線程---%@", [NSThread currentThread]); 22 23 //延遲執行,第二種方式 24 //可以安排其線程(1),主隊列 25 dispatch_queue_t queue= dispatch_get_main_queue(); 26 dispatch_after(dispatch_time(DISPATCH_TIME_NOW, (int64_t)(5.0 * NSEC_PER_SEC)), queue, ^{ 27 NSLog(@"主隊列--延遲執行------%@",[NSThread currentThread]); 28 }); 29 30 //可以安排其線程(2),并發隊列 31 //1.獲取全局并發隊列 32 dispatch_queue_t queue1= dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0); 33 //2.計算任務執行的時間 34 dispatch_time_t when=dispatch_time(DISPATCH_TIME_NOW, (int64_t)(5.0 * NSEC_PER_SEC)); 35 //3.會在when這個時間點,執行queue中的這個任務 36 dispatch_after(when, queue1, ^{ 37 NSLog(@"并發隊列-延遲執行------%@",[NSThread currentThread]); 38 }); 39 } 40 41 @end延遲執行:不需要再寫方法,且它還傳遞了一個隊列,我們可以指定并安排其線程。
如果隊列是主隊列,那么就在主線程執行,如果隊列是并發隊列,那么會新開啟一個線程,在子線程中執行。
?
二、一次性代碼
1.實現一次性代碼
需求:點擊控制器只有第一次點擊的時候才打印。
實現代碼:
1 //2 // YYViewController.m3 // 03-GCD常見使用(一次性代碼)4 //5 // Created by apple on 14-6-25.6 // Copyright (c) 2014年 itcase. All rights reserved.7 //8 9 #import "YYViewController.h" 10 11 @interface YYViewController () 12 @property(nonatomic,assign) BOOL log; 13 @end 14 15 @implementation YYViewController 16 17 -(void)touchesBegan:(NSSet *)touches withEvent:(UIEvent *)event 18 { 19 if (_log==NO) { 20 NSLog(@"該行代碼只執行一次"); 21 _log=YES; 22 } 23 } 24 @end缺點:這是一個對象方法,如果又創建一個新的控制器,那么打印代碼又會執行,因為每個新創建的控制器都有自己的布爾類型,且新創建的默認為NO,因此不能保證改行代碼在整個程序中只打印一次。
2.使用dispatch_once一次性代碼
使用dispatch_once函數能保證某段代碼在程序運行過程中只被執行1次
static?dispatch_once_t?onceToken;
dispatch_once(&onceToken, ^{
? ??//?只執行1次的代碼(這里面默認是線程安全的)
});
整個程序運行過程中,只會執行一次。
代碼示例:
1 //2 // YYViewController.m3 // 03-GCD常見使用(一次性代碼)4 //5 // Created by apple on 14-6-25.6 // Copyright (c) 2014年 itcase. All rights reserved.7 //8 9 #import "YYViewController.h" 10 11 @interface YYViewController () 12 @property(nonatomic,assign) BOOL log; 13 @end 14 15 @implementation YYViewController 16 17 //-(void)touchesBegan:(NSSet *)touches withEvent:(UIEvent *)event 18 //{ 19 // if (_log==NO) { 20 // NSLog(@"該行代碼只執行一次"); 21 // _log=YES; 22 // } 23 //} 24 25 -(void)touchesBegan:(NSSet *)touches withEvent:(UIEvent *)event 26 { 27 static dispatch_once_t onceToken; 28 dispatch_once(&onceToken, ^{ 29 NSLog(@"該行代碼只執行一次"); 30 }); 31 } 32 @end效果(程序運行過程中,打印代碼只會執行一次):
三、隊列組
需求:從網絡上下載兩張圖片,把兩張圖片合并成一張最終顯示在view上。
1.第一種方法
代碼示例:
1 //2 // YYViewController.m3 // 04-GCD基本使用(隊列組下載圖片)4 //5 // Created by apple on 14-6-25.6 // Copyright (c) 2014年 itcase. All rights reserved.7 //8 9 #import "YYViewController.h" 10 //宏定義全局并發隊列 11 #define global_quque dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0) 12 //宏定義主隊列 13 #define main_queue dispatch_get_main_queue() 14 15 @interface YYViewController () 16 @property (weak, nonatomic) IBOutlet UIImageView *imageView1; 17 @property (weak, nonatomic) IBOutlet UIImageView *imageView2; 18 @property (weak, nonatomic) IBOutlet UIImageView *imageView3; 19 20 @end 21 22 @implementation YYViewController 23 24 - (void)viewDidLoad 25 { 26 [super viewDidLoad]; 27 } 28 -(void)touchesBegan:(NSSet *)touches withEvent:(UIEvent *)event 29 { 30 //獲取全局并發隊列 31 // dispatch_queue_t queue= dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0); 32 //獲取主隊列 33 // dispatch_queue_t queue= dispatch_get_main_queue(); 34 35 // 圖片1:http://d.hiphotos.baidu.com/baike/c0%3Dbaike80%2C5%2C5%2C80%2C26/sign=2b9a12172df5e0fefa1581533d095fcd/cefc1e178a82b9019115de3d738da9773912ef00.jpg 36 // 圖片2:http://h.hiphotos.baidu.com/baike/c0%3Dbaike80%2C5%2C5%2C80%2C26/sign=f47fd63ca41ea8d39e2f7c56f6635b2b/1e30e924b899a9018b8d3ab11f950a7b0308f5f9.jpg 37 dispatch_async(global_quque, ^{ 38 //下載圖片1 39 UIImage *image1= [self imageWithUrl:@"http://d.hiphotos.baidu.com/baike/c0%3Dbaike80%2C5%2C5%2C80%2C26/sign=2b9a12172df5e0fefa1581533d095fcd/cefc1e178a82b9019115de3d738da9773912ef00.jpg"]; 40 NSLog(@"圖片1下載完成---%@",[NSThread currentThread]); 41 42 //下載圖片2 43 UIImage *image2= [self imageWithUrl:@"http://h.hiphotos.baidu.com/baike/c0%3Dbaike80%2C5%2C5%2C80%2C26/sign=f47fd63ca41ea8d39e2f7c56f6635b2b/1e30e924b899a9018b8d3ab11f950a7b0308f5f9.jpg"]; 44 NSLog(@"圖片2下載完成---%@",[NSThread currentThread]); 45 46 //回到主線程顯示圖片 47 dispatch_async(main_queue, ^{ 48 NSLog(@"顯示圖片---%@",[NSThread currentThread]); 49 self.imageView1.image=image1; 50 self.imageView2.image=image2; 51 //合并兩張圖片 52 UIGraphicsBeginImageContextWithOptions(CGSizeMake(200, 100), NO, 0.0); 53 [image1 drawInRect:CGRectMake(0, 0, 100, 100)]; 54 [image2 drawInRect:CGRectMake(100, 0, 100, 100)]; 55 self.imageView3.image=UIGraphicsGetImageFromCurrentImageContext(); 56 //關閉上下文 57 UIGraphicsEndImageContext(); 58 NSLog(@"圖片合并完成---%@",[NSThread currentThread]); 59 }); 60 // 61 }); 62 } 63 64 //封裝一個方法,傳入一個url參數,返回一張網絡上下載的圖片 65 -(UIImage *)imageWithUrl:(NSString *)urlStr 66 { 67 NSURL *url=[NSURL URLWithString:urlStr]; 68 NSData *data=[NSData dataWithContentsOfURL:url]; 69 UIImage *image=[UIImage imageWithData:data]; 70 return image; 71 } 72 @end顯示效果:
打印查看:
問題:這種方式的效率不高,需要等到圖片1.圖片2都下載完成后才行。
提示:使用隊列組可以讓圖片1和圖片2的下載任務同時進行,且當兩個下載任務都完成的時候回到主線程進行顯示。
2.使用隊列組解決
步驟:
創建一個組
開啟一個任務下載圖片1
?開啟一個任務下載圖片2
同時執行下載圖片1\下載圖片2操作
等group中的所有任務都執行完畢, 再回到主線程執行其他操作
代碼示例
1 //2 // YYViewController.m3 // 04-GCD基本使用(隊列組下載圖片)4 //5 // Created by apple on 14-6-25.6 // Copyright (c) 2014年 itcase. All rights reserved.7 //8 9 #import "YYViewController.h"10 //宏定義全局并發隊列11 #define global_quque dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0)12 //宏定義主隊列13 #define main_queue dispatch_get_main_queue()14 15 @interface YYViewController ()16 @property (weak, nonatomic) IBOutlet UIImageView *imageView1;17 @property (weak, nonatomic) IBOutlet UIImageView *imageView2;18 @property (weak, nonatomic) IBOutlet UIImageView *imageView3;19 20 @end21 22 @implementation YYViewController23 24 - (void)viewDidLoad25 {26 [super viewDidLoad];27 }28 -(void)touchesBegan:(NSSet *)touches withEvent:(UIEvent *)event29 {30 // 圖片1:http://d.hiphotos.baidu.com/baike/c0%3Dbaike80%2C5%2C5%2C80%2C26/sign=2b9a12172df5e0fefa1581533d095fcd/cefc1e178a82b9019115de3d738da9773912ef00.jpg31 // 圖片2:http://h.hiphotos.baidu.com/baike/c0%3Dbaike80%2C5%2C5%2C80%2C26/sign=f47fd63ca41ea8d39e2f7c56f6635b2b/1e30e924b899a9018b8d3ab11f950a7b0308f5f9.jpg32 33 34 //1.創建一個隊列組35 dispatch_group_t group = dispatch_group_create();36 37 //2.開啟一個任務下載圖片138 __block UIImage *image1=nil;39 dispatch_group_async(group, global_quque, ^{40 image1= [self imageWithUrl:@"http://d.hiphotos.baidu.com/baike/c0%3Dbaike80%2C5%2C5%2C80%2C26/sign=2b9a12172df5e0fefa1581533d095fcd/cefc1e178a82b9019115de3d738da9773912ef00.jpg"];41 NSLog(@"圖片1下載完成---%@",[NSThread currentThread]);42 });43 44 //3.開啟一個任務下載圖片245 __block UIImage *image2=nil;46 dispatch_group_async(group, global_quque, ^{47 image2= [self imageWithUrl:@"http://h.hiphotos.baidu.com/baike/c0%3Dbaike80%2C5%2C5%2C80%2C26/sign=f47fd63ca41ea8d39e2f7c56f6635b2b/1e30e924b899a9018b8d3ab11f950a7b0308f5f9.jpg"];48 NSLog(@"圖片2下載完成---%@",[NSThread currentThread]);49 });50 51 //同時執行下載圖片1\下載圖片2操作52 53 //4.等group中的所有任務都執行完畢, 再回到主線程執行其他操作54 dispatch_group_notify(group,main_queue, ^{55 NSLog(@"顯示圖片---%@",[NSThread currentThread]);56 self.imageView1.image=image1;57 self.imageView2.image=image2;58 59 //合并兩張圖片60 //注意最后一個參數是浮點數(0.0),不要寫成0。61 UIGraphicsBeginImageContextWithOptions(CGSizeMake(200, 100), NO, 0.0);62 [image1 drawInRect:CGRectMake(0, 0, 100, 100)];63 [image2 drawInRect:CGRectMake(100, 0, 100, 100)];64 self.imageView3.image=UIGraphicsGetImageFromCurrentImageContext();65 //關閉上下文66 UIGraphicsEndImageContext();67 68 NSLog(@"圖片合并完成---%@",[NSThread currentThread]);69 });70 71 }72 -(void)download2image73 {74 //獲取全局并發隊列75 // dispatch_queue_t queue= dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0);76 //獲取主隊列77 // dispatch_queue_t queue= dispatch_get_main_queue();78 79 dispatch_async(global_quque, ^{80 //下載圖片181 UIImage *image1= [self imageWithUrl:@"http://news.baidu.com/z/resource/r/image/2014-06-22/2a1009253cf9fc7c97893a4f0fe3a7b1.jpg"];82 NSLog(@"圖片1下載完成---%@",[NSThread currentThread]);83 84 //下載圖片285 UIImage *image2= [self imageWithUrl:@"http://news.baidu.com/z/resource/r/image/2014-06-22/2a1009253cf9fc7c97893a4f0fe3a7b1.jpg"];86 NSLog(@"圖片2下載完成---%@",[NSThread currentThread]);87 88 //回到主線程顯示圖片89 dispatch_async(main_queue, ^{90 NSLog(@"顯示圖片---%@",[NSThread currentThread]);91 self.imageView1.image=image1;92 self.imageView2.image=image2;93 //合并兩張圖片94 UIGraphicsBeginImageContextWithOptions(CGSizeMake(200, 100), NO, 0.0);95 [image1 drawInRect:CGRectMake(0, 0, 100, 100)];96 [image2 drawInRect:CGRectMake(0, 0, 100, 100)];97 self.imageView3.image=UIGraphicsGetImageFromCurrentImageContext();98 //關閉上下文99 UIGraphicsEndImageContext(); 100 NSLog(@"圖片合并完成---%@",[NSThread currentThread]); 101 }); 102 // 103 }); 104 } 105 106 //封裝一個方法,傳入一個url參數,返回一張網絡上下載的圖片 107 -(UIImage *)imageWithUrl:(NSString *)urlStr 108 { 109 NSURL *url=[NSURL URLWithString:urlStr]; 110 NSData *data=[NSData dataWithContentsOfURL:url]; 111 UIImage *image=[UIImage imageWithData:data]; 112 return image; 113 } 114 @end打印查看(同時開啟了兩個子線程,分別下載圖片):
2.補充說明
有這么1種需求:
首先:分別異步執行2個耗時的操作
其次:等2個異步操作都執行完畢后,再回到主線程執行操作
?
如果想要快速高效地實現上述需求,可以考慮用隊列組
dispatch_group_t?group =??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(), ^{
? ??//?等前面的異步操作都執行完畢后,回到主線程...
});
?
轉載于:https://www.cnblogs.com/liyang31tg/p/4277114.html
總結
以上是生活随笔為你收集整理的IOS-网络(GCD)的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: 陈元方候袁公(陈元方候袁公原文及译文)
- 下一篇: 制作集团公司网站有哪些核心内容和功能