GCD&&单粒

GCD基本思想

  • GCD的基本思想是就将操作放在队列中去执行
    • 操作使用Blocks定义
    • 队列负责调度任务执行所在的线程以及具体的执行时间
    • 队列的特点是先进先出(FIFO)的,新添加至对列的操作都会排在队尾

GCD中的专用术语

  • 同步函数和异步函数主要影响:能不能开启新的线程

    • 同步函数:只是在当前线程中执行任务,不具备开启新线程的能力
    • 异步函数:可以在新的线程中执行任务,具备开启新线程的能力(特殊情况:在主队列中不会开启新线程)
  • 并发队列和串行队列主要影响:任务的执行方式

    • 并发队列:允许多个任务并发(同时)执行
    • 穿行队列:一个任务执行完毕后,再执行下一个任务

同步函数 && 异步函数的小差别

- (void)syncConcurrent
{
    // 1.获得全局的并发队列
    dispatch_queue_t queue = dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0);

    // 2.将任务加入队列
    dispatch_sync(queue, ^{
        NSLog(@"1-----%@", [NSThread currentThread]);
    });
    dispatch_sync(queue, ^{
        NSLog(@"2-----%@", [NSThread currentThread]);
    });
    dispatch_sync(queue, ^{
        NSLog(@"3-----%@", [NSThread currentThread]);
    });

    NSLog(@"syncConcurrent--------end");// 先打印上面的,在打印这一句
}
- (void)asyncConcurrent
{
    // 1.获得全局的并发队列
    dispatch_queue_t queue = dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0);

    // 2.将任务加入队列
    dispatch_async(queue, ^{
        for (NSInteger i = 0; i<10; i++) {
            NSLog(@"1-----%@", [NSThread currentThread]);
        }
    });
    dispatch_async(queue, ^{
        for (NSInteger i = 0; i<10; i++) {
            NSLog(@"2-----%@", [NSThread currentThread]);
        }
    });
    dispatch_async(queue, ^{
        for (NSInteger i = 0; i<10; i++) {
            NSLog(@"3-----%@", [NSThread currentThread]);
        }
    });

    NSLog(@"asyncConcurrent--------end");// 先打印这一句,再打印上面的
//    dispatch_release(queue);
}

NSLog(@”syncConcurrent——–end”);
NSLog(@”asyncConcurrent——–end”);
明白上面两行都是什么时候调用
同步函数:任务加入队列后,立刻执行
异步函数:任务加入队列后,等会执行,可以理解为asyncConcurrent函数执行完,在执行任务

串行队列&&主队列

  • GCD中获得串行队列有两种途径

  • 使用dispatch_queue_create函数创建串行队列

 // 创建串行队列(队列类型传递NULL或者DISPATCH_QUEUE_SERIAL)
dispatch_queue_t queue = dispatch_queue_create("AHUAN.queue", DISPATCH_QUEUE_SERIAL);
dispatch_queue_t queue = dispatch_queue_create("AHUAN.queue", NULL);
dispatch_queue_t queue = dispatch_queue_create("AHUAN.queue", NULL);
// 同步操作不会新建线程、操作顺序执行(一般不用)
dispatch_sync(queue , ^{
    NSLog(@"串行同步 %@", [NSThread currentThread]);
});

// 异步操作会新建一个线程、操作顺序执行(非常有用!)场景:既不影响主线程,又需要顺序执行的操作!
dispatch_async(queue , ^{
    NSLog(@"串行异步 %@", [NSThread currentThread]);
});
  • 使用主队列(跟住线程相关联的队列)
    • 主队列是GCD自带的一种特殊的串行队列
    • 放在主队列中的任务,都会放到主线程中
    • 使用dispatch_get_main_queue() 获得主队列
// 每一个应用程序对应唯一一个主队列,直接GET即可,在多线程开发中,使用主队列更新UI
dispatch_queue_t queue = dispatch_get_main_queue();

// 主队列中的操作都应该在主线程上顺序执行的,不存在异步的概念
dispatch_async(queue, ^{
    NSLog(@"主队列异步 %@", [NSThread currentThread]);
});

// 主队列中添加的同步操作永远不会被执行,会死锁
dispatch_sync(queue, ^{
    NSLog(@"主队列同步 %@", [NSThread currentThread]);
}); 

并发队列&&全局队列

  • GCD中获得并发队列也有两种途径
  • 手动创建并发队列
dispatch_queue_t queue = dispatch_queue_create("cn.itcast.demoqueue", DISPATCH_QUEUE_CONCURRENT);

// 同步操作不会新建线程,操作顺序执行
dispatch_sync(queue, ^{
    NSLog(@"并行同步 %@", [NSThread currentThread]);
});

// 异步操作会新建多个线程、操作无序执行(有用,容易出错!)
// 队列前如果有其他任务,会等待前面的任务完成之后再执行
// 场景:既不影响主线程,又不需要顺序执行的操作!

dispatch_async(queue, ^{
    NSLog(@"并行异步 %@", [NSThread currentThread]);
});
  • GCD默认已经提供了全局的并发队列,供整个应用使用,可以无需手动创建
// 全局队列是系统的,直接拿过来(GET)用就可以
// 与并行队列类似
dispatch_queue_t queue = dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0);

dispatch_queue_t queue = dispatch_get_global_queue(0, 0);
// 优先级 0 就代表 DISPATCH_QUEUE_PRIORITY_DEFAULT

这里写图片描述

不同队列中嵌套dispatch_sync的结果

// 全局队列,都在主线程上执行,不会死锁
dispatch_queue_t q = dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0);

// 并行队列,都在主线程上执行,不会死锁
dispatch_queue_t q = dispatch_queue_create("AHUNA.queue",DISPATCH_QUEUE_CONCURRENT);

// 串行队列,会死锁,但是会执行嵌套同步操作之前的代码
dispatch_queue_t q = dispatch_queue_create("AHUNA.queue", DISPATCH_QUEUE_SERIAL);

// 直接死锁
dispatch_queue_t q = dispatch_get_main_queue();
dispatch_sync(q, ^{
    NSLog(@"同步任务 %@", [NSThread currentThread]);
    dispatch_sync(q, ^{
        NSLog(@"同步任务 %@", [NSThread currentThread]);
    });
});

线程间的通信示例

  • 从子线程回到主线程
dispatch_async(dispatch_get_global_queue(0, 0), ^{
    // 执行耗时的异步操作...
    dispatch_async(dispatch_get_main_queue(), ^{
        // 回到主线程,执行UI刷新操作
    });
});

GCD常用函数

执行任务的函数dispatch_barrier_async

执行任务的函数

    dispatch_barrier_async(<#dispatch_queue_t queue#>, ^{
        <#code#>
    })
  • 在这之前的任务结束后它才执行,而且它后面的任务等它执行完之后才会执行
  • 这个queue不能是全局的并发队列,可以是我们自己创建的并发队列

一次性代码dispatch_once

  • 确保某段代码在程序运行过程中只被执行1次
    static dispatch_once_t onceToken;
    dispatch_once(&onceToken, ^{
       // 这里面的代码整个程序只执行一次(这里面默认是线程安全的)
    });

延时执行

  • 使用GCD函数
dispatch_after(dispatch_time(DISPATCH_TIME_NOW, (int64_t)(2.0 * NSEC_PER_SEC)), dispatch_get_main_queue(), ^{
    // 2秒后执行这里的代码...
});
  • 调用NSObject的方法
[self performSelector:@selector(run) withObject:nil afterDelay:2.0];
// 2秒后在调用self的run方法
  • 使用NSTimer
[NSTimer scheduledTimerWithTimeInterval:2.0 target:self selector:@selector(run) userInfo:nil repeats:NO];
// 2秒后在调用self的run方法

快速迭代

  • 使用dispatch_apply函数能进行快速迭代遍历
// size_t iterations代表执行多少次
dispatch_apply(<#size_t iterations#>, <#dispatch_queue_t queue#>, ^(size_t index) {
    <#code#>
    // index顺序不确定
});

组队列

// 分别异步执行两个耗时的操作(下载图片),等2个异步操作都执行完毕后,再异步执行一个耗时操作(合成图片)
// 然后在回到主线程中刷新UI界面

    dispatch_queue_t queue = dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0);
    // 创建一个队列组
    dispatch_group_t group = dispatch_group_create();

    // 1.下载图片1
    dispatch_group_async(group, queue, ^{
        // 图片的网络路径
        NSURL *url = [NSURL URLWithString:@"http://img.pconline.com.cn/images/photoblog/9/9/8/1/9981681/200910/11/1255259355826.jpg"];

        // 加载图片
        NSData *data = [NSData dataWithContentsOfURL:url];

        // 生成图片
        self.image1 = [UIImage imageWithData:data];
    });

    // 2.下载图片2
    dispatch_group_async(group, queue, ^{
        // 图片的网络路径
        NSURL *url = [NSURL URLWithString:@"http://pic38.nipic.com/20140228/5571398_215900721128_2.jpg"];

        // 加载图片
        NSData *data = [NSData dataWithContentsOfURL:url];

        // 生成图片
        self.image2 = [UIImage imageWithData:data];
    });

    // 3.将图片1、图片2合成一张新的图片
    dispatch_group_notify(group, queue, ^{
        // 开启新的图形上下文
        UIGraphicsBeginImageContext(CGSizeMake(100, 100));

        // 绘制图片
        [self.image1 drawInRect:CGRectMake(0, 0, 50, 100)];
        [self.image2 drawInRect:CGRectMake(50, 0, 50, 100)];

        // 取得上下文中的图片
        UIImage *image = UIGraphicsGetImageFromCurrentImageContext();

        // 结束上下文
        UIGraphicsEndImageContext();

        // 回到主线程显示图片
        dispatch_async(dispatch_get_main_queue(), ^{
            // 4.将新图片显示出来 
            self.imageView.image = image;
        });
    });

单粒模式

  • .m 中保留一个全局的static的实例:static id_instance
// 重写allocWithZone:方法,在这里创建一个唯一的实例(注意线程安全)
+(instancetype)allocWithZone:(struct _NSZone *)zone{
    static dispatch_once_t onceToken;
    dispatch_once(&onceToken, ^{
        _instance = [super allocWithZone:zone];
    });
    return _instance;
}

// 提供1个类方法让外界访问唯一的实例
+ (instancetype)sharedInstance{
    static dispatch_once_t onceToken;
    dispatch_once(&onceToken, ^{
        _instance = [[self alloc] init];
    });
    return _instance;
}

// 实现copyWithZone:方法
- (id)copyWithZone:(struct _NSZone *)zone{
    return _instance;
}
  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值