多线程 - 08.GCD其他使用

来源:互联网 发布:网络兼职怎么做 编辑:程序博客网 时间:2024/06/06 15:45

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