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
复制代码

 

posted on   低头捡石頭  阅读(59)  评论(0编辑  收藏  举报

相关博文:
阅读排行:
· 全程不用写代码,我用AI程序员写了一个飞机大战
· DeepSeek 开源周回顾「GitHub 热点速览」
· 记一次.NET内存居高不下排查解决与启示
· MongoDB 8.0这个新功能碉堡了,比商业数据库还牛
· .NET10 - 预览版1新功能体验(一)
< 2025年3月 >
23 24 25 26 27 28 1
2 3 4 5 6 7 8
9 10 11 12 13 14 15
16 17 18 19 20 21 22
23 24 25 26 27 28 29
30 31 1 2 3 4 5

导航

统计

点击右上角即可分享
微信分享提示