iOS基础 - GCD:常用API
▶ 常用 API
在开发中,我们经常使用到的 API 有
// 任务只执行一次 dispatch_once() // 同步执行 dispatch_sync() // 异步执行 dispatch_async() dispatch_async_f() // 延迟到的时间点执行 dispatch_after() // 任务会重复执行 dispatch_apply() // 分组 dispatch_group_async() // 当某个分组的所有任务执行完毕后,此任务才会执行 dispatch_group_notify() // 将任务添加到队列中,此任务执行时其他任务停止 dispatch_barrier_async()
▶ 代码示例
延迟执行:常见的延时执行有两种方式
A. NSObject 方法:该方法在那个线程调用,那么方法就在哪个线程执行(通常是主线程)
[self performSelector:@selector() withObject:nil afterDelay:2.0]; // 2秒后执行(异步)
B. GCD
dispatch_after(dispatch_time(DISPATCH_TIME_NOW, (int64_t)(2.0 * NSEC_PER_SEC)), dispatch_get_main_queue(), ^{ // 2 秒后执行(异步) });
dispatch_once函数:保证某段代码在程序运行过程中只被执行 1 次
-(void)touchesBegan:(NSSet *)touches withEvent:(UIEvent *)event{ static dispatch_once_t onceToken; dispatch_once(&onceToken, ^{ NSLog(@"dispatch_once_t:该代码只会被执行 1 次"); }); }
dispatch_apply函数:往队列里边多次提交同一任务
dispatch_apply(3, dispatch_get_global_queue(0, 0), ^(size_t n) { for (int i = 0; i < 5; i ++) { NSLog(@"第%ld次,i = %d",n+1,i); } });
dispatch_group_t函数:队列组
A. 我们把下载好的两张图片合并成一张,最终将其显示在视图上。在使用队列组之前,你的实现可能如下
1 #import "ViewController.h" 2 #define SCREEN_WIDTH [UIScreen mainScreen].bounds.size.width 3 #define SCREENH_HEIGHT [UIScreen mainScreen].bounds.size.height 4 // 全局并发队列 5 #define global_quque dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0) 6 // 主队列 7 #define main_queue dispatch_get_main_queue() 8 // 图片地址 9 #define URL_P1 @"https://pic1.zhimg.com/v2-fff789aef40afbf05b8bb3ef0bbe1432_1440w.jpg?source=172ae18b" 10 #define URL_P2 @"https://c-ssl.duitang.com/uploads/item/201910/19/20191019235743_R4mMH.thumb.1000_0.jpeg" 11 @interface ViewController () 12 @property (weak, nonatomic) UIImageView *imageView1; // 图片1 13 @property (weak, nonatomic) UIImageView *imageView2; // 图片2 14 @property (weak, nonatomic) UIImageView *imageView3; // 图片3 15 16 @end 17 18 @implementation ViewController 19 20 - (void)viewDidLoad{ 21 [super viewDidLoad]; 22 self.view.backgroundColor = [UIColor cyanColor]; 23 24 // 图片宽/高 25 float W_IV = (SCREEN_WIDTH -30)/2; 26 float H_IV = 100.0; 27 28 // 用遍历的方式创建 3张 视图 29 for (int i = 0; i <3; i++) { 30 // 视图 31 UIImageView *IV = [[UIImageView alloc] init]; 32 IV.backgroundColor = [UIColor redColor]; 33 [self.view addSubview:IV]; 34 switch (i) { 35 case 0: 36 IV.frame = CGRectMake(10, 80, W_IV, H_IV); 37 self.imageView1 = IV; 38 break; 39 case 1: 40 IV.frame = CGRectMake(20+W_IV, 80, W_IV, H_IV); 41 self.imageView2 = IV; 42 break; 43 case 2: 44 IV.frame = CGRectMake((SCREEN_WIDTH-W_IV)/2, 220, W_IV, 2*H_IV); 45 self.imageView3 = IV; 46 break; 47 default: 48 break; 49 } 50 } 51 } 52 53 -(void)touchesBegan:(NSSet *)touches withEvent:(UIEvent *)event{ 54 55 // 图片宽高 56 float W_IV = (SCREEN_WIDTH -30)/2; 57 float H_IV = 100.0; 58 59 dispatch_async(global_quque, ^{ 60 61 // 下载图片 1 62 UIImage *image1= [self imageWithUrl:URL_P1]; 63 NSLog(@"图片1下载完成---%@",[NSThread currentThread]); 64 65 // 下载图片 2 66 UIImage *image2= [self imageWithUrl:URL_P2]; 67 NSLog(@"图片2下载完成---%@",[NSThread currentThread]); 68 69 // 回到主线程显示图片 70 dispatch_async(main_queue, ^{ 71 NSLog(@"显示图片---%@",[NSThread currentThread]); 72 // 方式 1 73 self.imageView1.image = image1; 74 // 方式 2 75 [self.imageView2 performSelector:@selector(setImage:) withObject:image2]; 76 77 // 合并两张图片 78 UIGraphicsBeginImageContextWithOptions(CGSizeMake(W_IV, 2*H_IV), NO, 0.0); 79 [image1 drawInRect:CGRectMake(0, 0, W_IV, H_IV)]; 80 [image2 drawInRect:CGRectMake(0, H_IV, W_IV, H_IV)]; 81 self.imageView3.image = UIGraphicsGetImageFromCurrentImageContext(); 82 // 关闭上下文 83 UIGraphicsEndImageContext(); 84 NSLog(@"图片合并完成---%@",[NSThread currentThread]); 85 }); 86 }); 87 } 88 89 // 下载图片 90 - (UIImage *)imageWithUrl:(NSString *)urlStr{ 91 NSURL *url = [NSURL URLWithString:urlStr]; 92 NSData *data = [NSData dataWithContentsOfURL:url]; 93 UIImage *image = [UIImage imageWithData:data]; 94 return image; 95 } 96 97 @end
日志信息
运行效果:这种方式的效率其实并不高,因为图片 1、图片 2 的下载任务并不是同时进行
B. 使用队列组,可以让图片 1 、图片 2 的下载任务并发进行
1 #import "ViewController.h" 2 #define SCREEN_WIDTH [UIScreen mainScreen].bounds.size.width 3 #define SCREENH_HEIGHT [UIScreen mainScreen].bounds.size.height 4 // 全局并发队列 5 #define global_quque dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0) 6 // 主队列 7 #define main_queue dispatch_get_main_queue() 8 // 图片地址 9 #define URL_P1 @"https://pic1.zhimg.com/v2-fff789aef40afbf05b8bb3ef0bbe1432_1440w.jpg?source=172ae18b" 10 #define URL_P2 @"https://c-ssl.duitang.com/uploads/item/201910/19/20191019235743_R4mMH.thumb.1000_0.jpeg" 11 @interface ViewController () 12 @property (weak, nonatomic) UIImageView *imageView1; 13 @property (weak, nonatomic) UIImageView *imageView2; 14 @property (weak, nonatomic) UIImageView *imageView3; 15 16 @end 17 18 @implementation ViewController 19 20 - (void)viewDidLoad{ 21 [super viewDidLoad]; 22 self.view.backgroundColor = [UIColor cyanColor]; 23 // 图片宽高 24 float W_IV = (SCREEN_WIDTH -30)/2; 25 float H_IV = 100.0; 26 27 // 创建视图 28 for (int i = 0; i <3; i++) { 29 UIImageView *IV = [[UIImageView alloc] init]; 30 IV.backgroundColor = [UIColor redColor]; 31 [self.view addSubview:IV]; 32 switch (i) { 33 case 0: 34 IV.frame = CGRectMake(10, 80, W_IV, H_IV); 35 self.imageView1 = IV; 36 break; 37 case 1: 38 IV.frame = CGRectMake(20+W_IV, 80, W_IV, H_IV); 39 self.imageView2 = IV; 40 break; 41 case 2: 42 IV.frame = CGRectMake((SCREEN_WIDTH-W_IV)/2, 220, W_IV, 2*H_IV); 43 self.imageView3 = IV; 44 break; 45 default: 46 break; 47 } 48 } 49 } 50 51 -(void)touchesBegan:(NSSet *)touches withEvent:(UIEvent *)event{ 52 53 // 图片宽高 54 float W_IV = (SCREEN_WIDTH -30)/2; 55 float H_IV = 100.0; 56 57 dispatch_group_t group = dispatch_group_create(); 58 __block UIImage *image1 = nil; 59 60 // 下载1 和 下载2 是并发的,会分别开辟新的线程 61 dispatch_group_async(group, global_quque, ^{ 62 image1= [self imageWithUrl:URL_P1]; 63 NSLog(@"图片1下载完成---%@",[NSThread currentThread]); 64 }); 65 66 __block UIImage *image2 = nil; 67 dispatch_group_async(group, global_quque, ^{ 68 image2= [self imageWithUrl:URL_P2]; 69 NSLog(@"图片2下载完成---%@",[NSThread currentThread]); 70 }); 71 72 73 // 待到 group 中的所有任务都执行完毕, 回到主线程刷新 UI 74 dispatch_group_notify(group,main_queue, ^{ 75 NSLog(@"显示图片---%@",[NSThread currentThread]); 76 self.imageView1.image = image1; 77 self.imageView2.image = image2; 78 79 // 合并两张图片 80 UIGraphicsBeginImageContextWithOptions(CGSizeMake(W_IV, 2*H_IV), NO, 0.0); 81 [image1 drawInRect:CGRectMake(0, 0, W_IV, H_IV)]; 82 [image2 drawInRect:CGRectMake(0, H_IV, W_IV, H_IV)]; 83 self.imageView3.image = UIGraphicsGetImageFromCurrentImageContext(); 84 // 关闭上下文 85 UIGraphicsEndImageContext(); 86 NSLog(@"图片合并完成---%@",[NSThread currentThread]); 87 }); 88 } 89 90 // 下载图片 91 -(UIImage *)imageWithUrl:(NSString *)urlStr{ 92 93 NSURL *url=[NSURL URLWithString:urlStr]; 94 NSData *data=[NSData dataWithContentsOfURL:url]; 95 UIImage *image=[UIImage imageWithData:data]; 96 return image; 97 } 98 99 @end
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· 全程不用写代码,我用AI程序员写了一个飞机大战
· DeepSeek 开源周回顾「GitHub 热点速览」
· 记一次.NET内存居高不下排查解决与启示
· MongoDB 8.0这个新功能碉堡了,比商业数据库还牛
· .NET10 - 预览版1新功能体验(一)