GCD的基本使用
一、主佇列介紹
主佇列:是和主執行緒相關聯的佇列,主佇列是GCD自帶的一種特殊的序列佇列,放在主佇列中得任務,都會放到主執行緒中執行。
提示:如果把任務放到主佇列中進行處理,那麼不論處理函式是非同步的還是同步的都不會開啟新的執行緒。獲取主佇列的方式:
程式碼如下:
dispatch_queue_t queue=dispatch_get_main_queue();
(1)使用非同步函式執行主佇列中得任務,程式碼示例:
- (void)viewDidLoad{
[super viewDidLoad];
//列印主執行緒
NSLog(@"列印主執行緒--%@", [NSThread mainThread]);
//1.獲取主佇列
dispatch_queue_t queue=dispatch_get_main_queue();
//2.把任務新增到主佇列中執行
dispatch_async(queue, ^{
NSLog(@"使用非同步函式執行主佇列中的任務1--%@",[NSThread currentThread]);
});
dispatch_async(queue, ^{
NSLog(@"使用非同步函式執行主佇列中的任務2--%@",[NSThread currentThread]);
});
dispatch_async(queue, ^{
NSLog(@"使用非同步函式執行主佇列中的任務3--%@",[NSThread currentThread]);
});
}```
執行結果:
![結果](http://upload-images.jianshu.io/upload_images/1803308-ef60529bbf50f770.png?imageMogr2/auto-orient/strip%7CimageView2/2/w/1240)
(2)使用同步函式,在主執行緒中執行主佇列中得任務,會發生死迴圈,任務無法往下執行。
***
**二、基本使用**
1.問題
任務1和任務2是在主執行緒執行還是子執行緒執行,還是單獨再開啟一個新的執行緒?
- (void)viewDidLoad{
[super viewDidLoad];
//開啟一個後臺執行緒,呼叫執行test方法
[self performSelectorInBackground:@selector(test) withObject:nil];
}
-(void)test{
NSLog(@"當前執行緒---%@",[NSThread currentThread]);
dispatch_queue_t queue = dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0);
//非同步函式
dispatch_async(queue, ^{
NSLog(@"任務1所在的執行緒----%@",[NSThread currentThread]);
});
//同步函式
dispatch_sync(queue, ^{
NSLog(@"任務2所在的執行緒----%@",[NSThread currentThread]);
});
}
列印結果:
![結果](http://upload-images.jianshu.io/upload_images/1803308-7dc7fbf42dd2d73f.png?imageMogr2/auto-orient/strip%7CimageView2/2/w/1240)
2.開啟子執行緒,載入圖片
//當手指觸控螢幕的時候,從網路上下載一張圖片到控制器的view上顯示
-(void)touchesBegan:(NSSet *)touches withEvent:(UIEvent *)event{
//1.獲取一個全域性序列佇列
dispatch_queue_t queue = dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0);
//2.把任務新增到佇列中執行
dispatch_async(queue, ^{
//列印當前執行緒
NSLog(@"%@",[NSThread currentThread]);
//3.從網路上下載圖片
NSURL *urlstr=[NSURL URLWithString:@"http://h.hiphotos.baidu.com/baike/w%3D268/sign=30b3fb747b310a55c424d9f28f444387/1e30e924b899a9018b8d3ab11f950a7b0308f5f9.jpg"];
NSData *data=[NSData dataWithContentsOfURL:urlstr];
UIImage *image=[UIImage imageWithData:data];
//提示
NSLog(@"圖片載入完畢");
//4.回到主執行緒,展示圖片
[self.imageView performSelectorOnMainThread:@selector(setImage:) withObject:image waitUntilDone:NO];
});
}
***
####* 執行緒間的通訊
(要求使用GCD的方式,在子執行緒載入圖片完畢後,主執行緒拿到載入的image重新整理UI介面。)
//4.回到主執行緒,展示圖片
NSObject回到主執行緒的方法
//[self.imageView performSelectorOnMainThread:@selector(setImage:) withObject:image waitUntilDone:NO];
GCD回到主執行緒的方法
dispatch_async(dispatch_get_main_queue(), ^{
self.imageView.image=image;
//列印當前執行緒
NSLog(@"%@",[NSThread currentThread]);
});
***
#### * GCD的常見用法
**一、延遲執行**
(1)呼叫NSObject的方法
[self performSelector:@selector(run) withObject:nil afterDelay:2.0];
//2秒後再呼叫self的run方法
//該方法在那個執行緒呼叫,那麼run就在哪個執行緒執行(當前執行緒),通常是主執行緒。```
(2)使用GCD函式
dispatch_after(dispatch_time(DISPATCH_TIME_NOW, (int64_t)(2.0 * NSEC_PER_SEC)), dispatch_get_main_queue(), ^{
// 2秒後非同步執行這裡的程式碼...
});```
延遲執行:不需要再寫方法,且它還傳遞了一個佇列,我們可以指定並安排其執行緒。
如果佇列是主佇列,那麼就在主執行緒執行,如果佇列是併發佇列,那麼會新開啟一個執行緒,在子執行緒中執行。
**二、一次性程式碼**
1.使用`dispatch_once`一次性程式碼
使用`dispatch_once`函式能保證某段程式碼在程式執行過程中只被執行1次
static dispatch_once_t onceToken;
dispatch_once(&onceToken, ^{
// 只執行1次的程式碼(這裡面預設是執行緒安全的)
});
**三、佇列組**
需求:從網路上下載兩張圖片,把兩張圖片合併成一張最終顯示在view上。
1.第一種方法
程式碼示例:
import "YYViewController.h"
//巨集定義全域性併發佇列
define global_quque dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0)
//巨集定義主佇列
define main_queue dispatch_get_main_queue()
@interface YYViewController ()
@property (weak, nonatomic) IBOutlet UIImageView *imageView1;
@property (weak, nonatomic) IBOutlet UIImageView *imageView2;
@property (weak, nonatomic) IBOutlet UIImageView *imageView3;
@end
@implementation YYViewController
- (void)viewDidLoad{
[super viewDidLoad];
}
-(void)touchesBegan:(NSSet *)touches withEvent:(UIEvent *)event{
//獲取全域性併發佇列
dispatch_queue_t global_queue = dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0);
//獲取主佇列
dispatch_queue_t main_queue = dispatch_get_main_queue();
dispatch_async(global_quque, ^{
//下載圖片1
UIImage *image1= [self imageWithUrl:@"http://d.hiphotos.baidu.com/baike/c0%3Dbaike80%2C5%2C5%2C80%2C26/sign=2b9a12172df5e0fefa1581533d095fcd/cefc1e178a82b9019115de3d738da9773912ef00.jpg"];
NSLog(@"圖片1下載完成---%@",[NSThread currentThread]);
//下載圖片2
UIImage *image2= [self imageWithUrl:@"http://h.hiphotos.baidu.com/baike/c0%3Dbaike80%2C5%2C5%2C80%2C26/sign=f47fd63ca41ea8d39e2f7c56f6635b2b/1e30e924b899a9018b8d3ab11f950a7b0308f5f9.jpg"];
NSLog(@"圖片2下載完成---%@",[NSThread currentThread]);
//回到主執行緒顯示圖片
dispatch_async(main_queue, ^{
NSLog(@"顯示圖片---%@",[NSThread currentThread]);
self.imageView1.image=image1;
self.imageView2.image=image2;
//合併兩張圖片
UIGraphicsBeginImageContextWithOptions(CGSizeMake(200, 100), NO, 0.0);
[image1 drawInRect:CGRectMake(0, 0, 100, 100)];
[image2 drawInRect:CGRectMake(100, 0, 100, 100)];
self.imageView3.image=UIGraphicsGetImageFromCurrentImageContext();
//關閉上下文
UIGraphicsEndImageContext();
NSLog(@"圖片合併完成---%@",[NSThread currentThread]);
});
});
}
//封裝一個方法,傳入一個url引數,返回一張網路上下載的圖片
-(UIImage *)imageWithUrl:(NSString *)urlStr{
NSURL *url=[NSURL URLWithString:urlStr];
NSData *data=[NSData dataWithContentsOfURL:url];
UIImage *image=[UIImage imageWithData:data];
return image;
}
@end```
列印結果:
問題:這種方式的效率不高,需要等到圖片1.圖片2都下載完成後才行。
提示:使用佇列組可以讓圖片1和圖片2的下載任務同時進行,且當兩個下載任務都完成的時候回到主執行緒進行顯示。
2.使用佇列組解決
步驟:
建立一個組
開啟一個任務下載圖片1
開啟一個任務下載圖片2
同時執行下載圖片1\下載圖片2操作
等group中的所有任務都執行完畢, 再回到主執行緒執行其他操作
#import "YYViewController.h"
//巨集定義全域性併發佇列
#define global_quque dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0)
//巨集定義主佇列
#define main_queue dispatch_get_main_queue()
@interface YYViewController ()
@property (weak, nonatomic) IBOutlet UIImageView *imageView1;
@property (weak, nonatomic) IBOutlet UIImageView *imageView2;
@property (weak, nonatomic) IBOutlet UIImageView *imageView3;
@end
@implementation YYViewController
- (void)viewDidLoad{
[super viewDidLoad];}
-(void)touchesBegan:(NSSet *)touches withEvent:(UIEvent *)event{
//1.建立一個佇列組
dispatch_group_t group = dispatch_group_create();
//2.開啟一個任務下載圖片1
__block UIImage *image1=nil;
dispatch_group_async(group, global_quque, ^{
image1= [self imageWithUrl:@"http://d.hiphotos.baidu.com/baike/c0%3Dbaike80%2C5%2C5%2C80%2C26/sign=2b9a12172df5e0fefa1581533d095fcd/cefc1e178a82b9019115de3d738da9773912ef00.jpg"];
NSLog(@"圖片1下載完成---%@",[NSThread currentThread]);
});
//3.開啟一個任務下載圖片2
__block UIImage *image2=nil;
dispatch_group_async(group, global_quque, ^{
image2= [self imageWithUrl:@"http://h.hiphotos.baidu.com/baike/c0%3Dbaike80%2C5%2C5%2C80%2C26/sign=f47fd63ca41ea8d39e2f7c56f6635b2b/1e30e924b899a9018b8d3ab11f950a7b0308f5f9.jpg"];
NSLog(@"圖片2下載完成---%@",[NSThread currentThread]);
});
//4.等group中的所有任務都執行完畢, 再回到主執行緒執行其他操作
dispatch_group_notify(group,main_queue, ^{
NSLog(@"顯示圖片---%@",[NSThread currentThread]);
self.imageView1.image=image1;
self.imageView2.image=image2;
//合併兩張圖片
//注意最後一個引數是浮點數(0.0),不要寫成0。
UIGraphicsBeginImageContextWithOptions(CGSizeMake(200, 100), NO, 0.0);
[image1 drawInRect:CGRectMake(0, 0, 100, 100)];
[image2 drawInRect:CGRectMake(100, 0, 100, 100)];
self.imageView3.image=UIGraphicsGetImageFromCurrentImageContext();
//關閉上下文
UIGraphicsEndImageContext();
NSLog(@"圖片合併完成---%@",[NSThread currentThread]);
});
}
補充說明
有這麼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(), ^{
// 等前面的非同步操作都執行完畢後,回到主執行緒...
});```
相關文章
- 執行緒7--GCD的基本使用執行緒GC
- GCD 中Group的使用GC
- iOS GCD入門和GCD對CPU多核的使用iOSGC
- GCD簡單使用GC
- iOS--GCD的API的理解與使用iOSGCAPI
- GCD之佇列的實現和使用GC佇列
- 奇怪的GCDGC
- (翻譯)給iOS開發者的GCD使用手冊iOSGC
- GCD Inside: GCD 宏GCIDE
- GCDGC
- GCD使用經驗與技巧淺談GC
- Vuex的基本使用Vue
- mongoose的基本使用Go
- mysqli的基本使用MySql
- mybatis的基本使用MyBatis
- RecyclerView 的基本使用View
- Bootstrap 的基本使用boot
- github的基本使用Github
- jQuery的基本使用jQuery
- Promise的基本使用Promise
- pymongo的基本使用Go
- pymssql的基本使用SQL
- 示波器的基本使用:
- luarocks 的基本使用
- git的基本使用Git
- GCD SUMGC
- GCD QueriesGC
- GCD Inside: GCD 資料結構GCIDE資料結構
- codechef Dynamic GCD [樹鏈剖分 gcd]GC
- 多個網路請求中GCD訊號量的使用GC
- ts + hooks 的基本使用Hook
- Nifi:nifi的基本使用Nifi
- JSCore的基本使用JS
- React ref的基本使用React
- AIDL的基本使用AI
- ViewDragHelper 的基本使用(一)View
- socket基本的API使用API
- 代理的基本使用(delegate)