隊列組 讓隊列里的任務同時執行,當任務都執行完畢時,再以通知的形式告訴程式員。舉例,同時下載兩張圖片,兩張圖片都下載完了,在合成成一張。 代碼: 日誌 效果: 如果不用隊列組,下載第一張圖片、下載第二張圖片、合併兩張圖片,就只能當做一個任務放入隊列中,不能同時下載兩張圖片,耗時幾乎多了一倍。因為,如 ...
隊列組
讓隊列里的任務同時執行,當任務都執行完畢時,再以通知的形式告訴程式員。舉例,同時下載兩張圖片,兩張圖片都下載完了,在合成成一張。
代碼:
#import "ViewController.h"
@interface ViewController ()
@property (weak, nonatomic) IBOutlet UIImageView *imageView1;
@property (weak, nonatomic) IBOutlet UIImageView *imageView2;
@property (weak, nonatomic) IBOutlet UIImageView *imageView3;
@end
@implementation ViewController
// 點擊屏幕開始下載圖片
- (void)touchesBegan:(NSSet<UITouch *> *)touches withEvent:(UIEvent *)event {
// 創建全局併發隊列
dispatch_queue_t queue = dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0);
// 創建隊列組
dispatch_group_t group = dispatch_group_create();
__block UIImage *image1 = nil;
// 開啟一個任務
dispatch_group_async(group, queue, ^{
NSLog(@"%@開始下載第一張圖片",[NSThread currentThread]);
NSString *strURL1 = @"http://h.hiphotos.baidu.com/zhidao/pic/item/6d81800a19d8bc3ed69473cb848ba61ea8d34516.jpg";
image1 = [self downloadImageWithURL:strURL1];
});
// 開啟一個任務
__block UIImage *image2 = nil;
dispatch_group_async(group, queue, ^{
NSLog(@"%@開始下載第二張圖片",[NSThread currentThread]);
NSString *strURL2 = @"http://h.hiphotos.baidu.com/zhidao/pic/item/0eb30f2442a7d9334f268ca9a84bd11372f00159.jpg";
image2 = [self downloadImageWithURL:strURL2];
});
// 同時執行下載圖片1\下載圖片2的操作
// 等group里的任務執行完畢,執行的操作
// 回到主線程顯示圖片
dispatch_group_notify(group, dispatch_get_main_queue(), ^{
NSLog(@"%@顯示圖片",[NSThread currentThread]);
self.imageView1.image = image1;
self.imageView2.image = image2;
// 合併兩張圖片圖片
UIGraphicsBeginImageContextWithOptions(CGSizeMake(100, 50), NO, 0.0);
[image1 drawInRect:CGRectMake(0, 0, 50, 50)];
[image2 drawInRect:CGRectMake(50, 0, 50, 50)];
self.imageView3.image = UIGraphicsGetImageFromCurrentImageContext();
UIGraphicsEndImageContext();
});
}
- (UIImage *)downloadImageWithURL : (NSString *)strURL {
NSURL *url = [NSURL URLWithString:strURL];
return [UIImage imageWithData:[NSData dataWithContentsOfURL:url]];
}
@end
日誌
2016-11-05 09:03:49.300 TTTTTTTTTT[2543:26927] <NSThread: 0x7ba80500>{number = 3, name = (null)}開始下載第一張圖片
2016-11-05 09:03:49.301 TTTTTTTTTT[2543:28894] <NSThread: 0x7ba80b10>{number = 4, name = (null)}開始下載第二張圖片
2016-11-05 09:03:49.453 TTTTTTTTTT[2543:26806] <NSThread: 0x79773680>{number = 1, name = main}顯示圖片
效果:
如果不用隊列組,下載第一張圖片、下載第二張圖片、合併兩張圖片,就只能當做一個任務放入隊列中,不能同時下載兩張圖片,耗時幾乎多了一倍。因為,如果你不這樣做(當做一個任務放入隊列中),你不知道兩張圖片什麼時候下載完,誰先下載完,因為每次都不確定,不知道什麼時候合併圖片。現在用group,由系統來幫我們監聽兩張圖片下載的進度,咱們只要把兩張圖片都下載完的程式寫寫進dispatch_group_notify就好了。
延遲執行
延遲執行就是讓程式過一會在執行某一段代碼。用兩種方法:
- (void)performSelector:(SEL)aSelector withObject:(nullable id)anArgument afterDelay:(NSTimeInterval)delay; dispatch_after(dispatch_time_t when, dispatch_queue_t queue, dispatch_block_t block);
代碼
- (void)viewDidLoad {
[super viewDidLoad];
// 第一種
[self performSelector:@selector(run) withObject:nil afterDelay:2];
// 第二種 可以安排執行的隊列 3秒後執行
// 主隊列
dispatch_after(dispatch_time(DISPATCH_TIME_NOW, (int64_t)(3 * NSEC_PER_SEC)), dispatch_get_main_queue(), ^{
NSLog(@"當前線程2%@",[NSThread currentThread]);
NSLog(@"GCD主隊列過一會執行我");
});
// 全局併發隊列
dispatch_queue_t queue = dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0);
dispatch_after(dispatch_time(DISPATCH_TIME_NOW, (int64_t)(3 * NSEC_PER_SEC)), queue, ^{
NSLog(@"當前線程3%@",[NSThread currentThread]);
NSLog(@"GCD全局併發隊列過一會執行我");
});
}
- (void)run {
NSLog(@"當前線程1%@",[NSThread currentThread]);
NSLog(@"過一會執行我");
}
日誌
2016-11-05 09:27:04.903 TTTTTTTTTT[3439:39246] 當前線程1<NSThread: 0x7b6629a0>{number = 1, name = main}
2016-11-05 09:27:04.903 TTTTTTTTTT[3439:39246] 過一會執行我
2016-11-05 09:27:06.176 TTTTTTTTTT[3439:39246] 當前線程2<NSThread: 0x7b6629a0>{number = 1, name = main}
2016-11-05 09:27:06.176 TTTTTTTTTT[3439:39291] 當前線程3<NSThread: 0x7d175a90>{number = 3, name = (null)}
2016-11-05 09:27:06.177 TTTTTTTTTT[3439:39246] GCD主隊列過一會執行我
2016-11-05 09:27:06.177 TTTTTTTTTT[3439:39291] GCD全局併發隊列過一會執行我
延遲執行我們常用的可能是第一種方法。從那個線程中調用“ performSelector”,run方法就在哪個線程中執行可,一般是主線程。第二種方法是可以自定義方法執行的隊列,可以是主隊列,也可以是全局隊列。本人比較喜歡用block,所以喜歡第二種,因為都寫在一起,增加了代碼的可讀性。
一次性代碼
一次性代碼主要是在單例中應用。
#import "Person.h"
@implementation Person
static Person *person;
// 1
- (instancetype)shareInstance1 {
static dispatch_once_t onceToken;
dispatch_once(&onceToken, ^{
person = [[Person alloc] init];
});
return person;
}
// 2.
- (instancetype)shareInstace2 {
if (!person) {
person = [[Person alloc] init];
}
return person;
}
@end
dispatch_once里的代碼在整個程式運行過程中就執行一次!!!所以你有這方面的需求,也可以用這個。
其實關於GCD,今天是最後一篇文章了,其實GCD還有很多地方我沒有講到,一方面是我水平有限,一方面是不常用。從下一篇開始,我就開始講NSOperation了。例外,如果大家關於GCD還有什麼想知道的,可以留言,我知道的一定告訴。