多线程 - 08.GCD其他使用

1.GCD线程之间的通信

  • 使用异步函数+除了主队列之外的队列创建子线程,在子线程中执行下载操作(耗时操作)
  • 在子线程中添加任务到主队列(更新UI操作),同步异步都可
-(void)touchesBegan:(NSSet *)touches withEvent:(UIEvent *)event{
    // 1.创建并发队列
    dispatch_queue_t queue = dispatch_get_global_queue(0, 0);
    // 2.调用异步函数,新建子线程,做好事操作
    dispatch_async(queue, ^{
        // 2.1.下载图片
        NSURL *url = [NSURL URLWithString:@"http://pic.4j4j.cn/upload/pic/20130531/07ed5ea485.jpg"];
        NSData *data = [NSData dataWithContentsOfURL:url];
        // 2.2 将二进制转换为图片
        UIImage *image = [UIImage imageWithData:data];
        // 2.3 回到主线程更新UI
        /*
         技巧:
         如果想等UI更新完毕再执行后面的代码, 那么使用同步函数
         如果不想等UI更新完毕就需要执行后面的代码, 那么使用异步函数
         */
        dispatch_sync(dispatch_get_main_queue(), ^{
            self.iv.image = image;
        });
        NSLog(@"设置图片完毕 %@", image);
    });
}

2.延时操作

  • 1.利用定时器实现
[NSTimer scheduledTimerWithTimeInterval:3.0 target:self selector:@selector(demo) userInfo:nil repeats:NO];
-(void)demo{
    NSLog(@"延时操作");
}
  • 2.利用performSelector方法
[self performSelector:@selector(demo) withObject:nil afterDelay:3.0];
-(void)demo{
    NSLog(@"延时操作");
}
  • 3.利用GCD的dispatch_after方法
-(void)delayGCD{
    // 第一个参数输入需要延时的时间,单位纳秒
    // block为延时操作任务
    // 该方法中, 会根据传入的队列来决定回掉block在哪个线程中执行
    // 如果传入的是主队列, 那么block会在主线程调用
    // 如果传入的是全局队列, 那么block会在子线程中调用
    dispatch_after(dispatch_time(DISPATCH_TIME_NOW, (int64_t)(3.0 * NSEC_PER_SEC)), dispatch_get_main_queue(), ^{
        NSLog(@"3秒后执行 %@",[NSThread currentThread]);
    });
}

3.一次性代码

  • 注意,一次性代码永远只执行一次
  • 一次性代码和懒加载不能混用,懒加载在需要的时候被创建,销毁后,再次加载仍然会重新创建,而一次性代码在整个程序过程中只会被执行一次
  • 通常一次性代码可以用来创建单例对象
-(void)onceTakon{
    /*
     静态变量用来记录,代码是否被执行,并且一次性代码默认是线程安全的
     */
    static dispatch_once_t onceToken;
    dispatch_once(&onceToken, ^{
        NSLog(@"一次性代码");
    });
}

4.快速迭代

  • 使用dispatch_apply函数能进行快速迭代遍历
  • 使用快速迭代要比for循环遍历效率要高
// 快速迭代
-(void)apply{
    // 获取文件路径
    NSString *sourceFile = @"/Users/liuzhouji/Desktop/abc";
    NSString *resultFile = @"/Users/liuzhouji/Desktop/zj";
    // 获取原文件中所有内容
    NSFileManager *manager = [NSFileManager defaultManager];
    NSArray *files = [manager subpathsAtPath:sourceFile];
    // 遍历数组,拼接文件路径
    /* 参数解释
     第一个参数: 需要遍历几次
     第二个参数: 决定第三个参数的block在哪个线程中执行
     第三个参数: 回掉
     */
    dispatch_apply(files.count, dispatch_get_global_queue(0, 0), ^(size_t idx) {

        // 获取每一个文件名
        NSString *fileName = files[idx];
        // 生成原文件和目标文件的绝对路径
        NSString *sourcePath = [sourceFile stringByAppendingPathComponent:fileName];
        NSString *desPath = [resultFile stringByAppendingPathComponent:fileName];
        // 利用fileManager拷贝文件
        [manager moveItemAtPath:sourcePath toPath:desPath error:nil];
    });
}

5.栅栏

  • 功能:
    • 1.拦截前面的任务, 只有先添加到队列中的任务=执行完毕, 才会执行栅栏添加的任务
    • 2.如果栅栏后面还有其它的任务,那么必须等栅栏执行完毕才会执行后面的其它任务
  • 注意点:
    • 1.如果想要使用栅栏, 那么就不能使用全局的并发队列
    • 2.如果想使用栅栏,那么所有的任务都必须添加到同一个队列中
/**
 *  栅栏,实现等待图片下载完毕之后再执行刷新UI的操作
 */
- (void)barrier
{
    dispatch_queue_t queue = dispatch_queue_create("zj.queue", DISPATCH_QUEUE_CONCURRENT);

    __block UIImage *image1 = nil;
    __block UIImage *image2 = nil;
    // 1.开启一个新的线程下载第一张图片
    dispatch_async(queue, ^{
        NSURL *url = [NSURL URLWithString:@"http://h.hiphotos.baidu.com/image/pic/item/77c6a7efce1b9d1632701663f5deb48f8c546479.jpg"];
        NSData *data = [NSData dataWithContentsOfURL:url];
        UIImage *image = [UIImage imageWithData:data];
        image1 = image;
        NSLog(@"图片1下载完毕");
    });
    // 2.开启一个新的线程下载第二张图片
    dispatch_async(queue, ^{
        NSURL *url = [NSURL URLWithString:@"http://f.hiphotos.baidu.com/image/pic/item/18d8bc3eb13533fa0f2eb8c0acd3fd1f40345b47.jpg"];
        NSData *data = [NSData dataWithContentsOfURL:url];
        UIImage *image = [UIImage imageWithData:data];
        image2 = image;
        NSLog(@"图片2下载完毕");
    });

    // 3.开启一个新的线程, 合成图片
    // 栅栏
    // 功能:
    // 1.拦截前面的任务, 只有先添加到队列中的任务=执行完毕, 才会执行栅栏添加的任务
    // 2.如果栅栏后面还有其它的任务, 那么必须等栅栏执行完毕才会执行后面的其它任务
    // 注意点:
    // 1.如果想要使用栅栏, 那么就不能使用全局的并发队列
    // 2.如果想使用栅栏, 那么所有的任务都必须添加到同一个队列中
    dispatch_barrier_async(queue, ^{
        NSLog(@"%@ %@", image1, image2);
        // 1.开启图片上下文
        UIGraphicsBeginImageContext(CGSizeMake(200, 200));
        // 2.将第一张图片画上去
        [image1 drawInRect:CGRectMake(0, 0, 100, 200)];
        // 3.将第二张图片画上去
        [image2 drawInRect:CGRectMake(100, 0, 100, 200)];
        // 4.从上下文中获取绘制好的图片
        UIImage *newImage = UIGraphicsGetImageFromCurrentImageContext();
        // 5.关闭上下文
        UIGraphicsEndImageContext();

        // 4.回到主线程更新UI
        dispatch_async(dispatch_get_main_queue(), ^{
            self.iv.image = newImage;
            [UIImagePNGRepresentation(newImage) writeToFile:@"/Users/xiaomage/Desktop/abc/123.png" atomically:YES];
        });

        NSLog(@"栅栏执行完毕了");
    });
    dispatch_async(queue, ^{
        NSLog(@"1---------");
    });
    dispatch_async(queue, ^{
        NSLog(@"2---------");
    });
    dispatch_async(queue, ^{
        NSLog(@"3---------");
    });
    /*输出结果:
     图片1下载完毕
     图片2下载完毕
     栅栏执行完毕了
     2---------
     1---------
     3---------
     */
}

6.队列组

  • 利用队列组可以实现和栅栏类似的效果
  • 可以让耗时操作执行完后再去执行更新UI的操作
-(void)group{
    // 创建队列
     dispatch_queue_t queue = dispatch_get_global_queue(0, 0);
    // 创建组
    dispatch_group_t group = dispatch_group_create();

    __block UIImage *image1 = nil;
    __block UIImage *image2 = nil;
    // 添加队列到队列组
    // 下载第一张图片
    dispatch_group_async(group, queue, ^{
        NSURL *url = [NSURL URLWithString:@"http://h.hiphotos.baidu.com/image/pic/item/77c6a7efce1b9d1632701663f5deb48f8c546479.jpg"];
        NSData *data = [NSData dataWithContentsOfURL:url];
        UIImage *image = [UIImage imageWithData:data];
        image1 = image;
        NSLog(@"图片1下载完毕");
    });
    // 下载第二张图片
    dispatch_group_async(group, queue, ^{
        NSURL *url = [NSURL URLWithString:@"http://f.hiphotos.baidu.com/image/pic/item/18d8bc3eb13533fa0f2eb8c0acd3fd1f40345b47.jpg"];
        NSData *data = [NSData dataWithContentsOfURL:url];
        UIImage *image = [UIImage imageWithData:data];
        image2 = image;
        NSLog(@"图片2下载完毕");
    });
    // 只要将队列放到group中, 队列中的任务执行完毕, group就会发出一个通知
    dispatch_group_notify(group, queue, ^{
        NSLog(@"%@ %@", image1, image2);
        // 1.开启图片上下文
        UIGraphicsBeginImageContext(CGSizeMake(200, 200));
        // 2.将第一张图片画上去
        [image1 drawInRect:CGRectMake(0, 0, 100, 200)];
        // 3.将第二张图片画上去
        [image2 drawInRect:CGRectMake(100, 0, 100, 200)];
        // 4.从上下文中获取绘制好的图片
        UIImage *newImage = UIGraphicsGetImageFromCurrentImageContext();
        // 5.关闭上下文
        UIGraphicsEndImageContext();

        // 回到主线程,更新UI
        dispatch_async(dispatch_get_main_queue(), ^{
            self.iv.image = newImage;
            [UIImagePNGRepresentation(newImage) writeToFile:@"/Users/xiaomage/Desktop/abc/123.png" atomically:YES];
        });
    });
}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值