当前位置:   article > 正文

多线程(二):GCD的基本使用,同步函数和异步函数,串行队列和并发队列,GCD队列组,栅栏函数,GCD单例_uigcd

uigcd
  • 什么是GCD

    1)全称是Grand Central Dispatch,可译为“牛逼的中枢调度器”

    2)纯C语言,提供了非常多强大的函数

  • GCD的优势

    1)GCD是苹果为多核并行运算提出的解决方案。

    2)GCD会自动利用更多的CPU内核(比如双核,四核)。

    3)GCD会自动管理线程的生命周期(创建线程,调度任务)。

  • 任务和队列

    1)任务:执行什么操作

    2)队列:用来存放任务

  • GCD的使用就两个步骤

     1)定制任务(确定想做的事)

     2)将任务添加到队列(GCD会自动将队列中的任务取出,放到对应的线程中去执行; 任务的取出遵循队列的FIFO原则:先进先出,后进后出(栈是先进后出))

  • 执行任务

   GCD中有2个用来执行任务的常用函数

   1)  用同步的方式执行任务

    dispatch_sync(dispatch_queue_t  queue, dispatch_block_t block): queue: 队列  block: 任务

   2)用异步的方式执行任务

    dispatch_async(dispatch_queue_t  queue, dispatch_block_t block)

  • 同步和异步的区别

   1)同步:只能在当前的线程中执行任务,不具备开启新线程的能力

   2)异步:可以在新的线程中执行任务,具备开启新线程的能力

  • 队列的类型

    GCD的队列可以分为两大类型

    1. 并发队列

    1) 可以让多个任务并发同时执行(自动开启多个线程自动执行任务)

    2)并发功能只有在异步(dispatch_async)函数下才有效

    2. 串行队列

    1)让任务一个接一个的执行(一个任务执行完毕后,再执行下一个任务)

  • 容易混淆的术语

       有四个术语比较容易混淆:同步,异步,并发,串行

     1. 同步和异步的主要区别:能不能开启新的线程

     1)同步:只是在当前线程中执行任务,不具备开启新线程的能力

     2)异步:可以在新的线程中执行,具备开启新线程的能力

     2. 并发和串行的主要区别:任务的执行方式

      1)并发:允许多个任务并发(同时)执行

      2)串行:一个任务执行完毕后,再执行下一个任务


GCD的基本使用

  1. #import "ViewController.h"
  2. @interface ViewController ()
  3. @end
  4. @implementation ViewController
  5. #pragma mark ----------------------
  6. #pragma Events
  7. -(void)touchesBegan:(NSSet<UITouch *> *)touches withEvent:(UIEvent *)event
  8. {
  9. // [NSThread detachNewThreadSelector:@selector(syncMain) toTarget:self withObject:nil];
  10. [self asyncConcurrent];
  11. }
  12. #pragma mark ----------------------
  13. #pragma Methods
  14. //异步函数+并发队列:会开启多条线程,队列中的任务是并发执行
  15. //注意:并不是有多少个任务就开启多少个线程,是由系统内部决定的
  16. -(void)asyncConcurrent
  17. {
  18. //1.创建队列
  19. /*
  20. 第一个参数:C语言的字符串,标签
  21. 第二个参数:队列的类型
  22. DISPATCH_QUEUE_CONCURRENT:并发
  23. DISPATCH_QUEUE_SERIAL:串行
  24. */
  25. //dispatch_queue_t queue = dispatch_queue_create("com.www.download", DISPATCH_QUEUE_CONCURRENT);
  26. //获得全局并发队列
  27. /*
  28. 第一个参数:优先级
  29. 第二个参数:
  30. */
  31. dispatch_queue_t queue = dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0);
  32. NSLog(@"---satrt----");
  33. //2.1>封装任务2>添加任务到队列中
  34. /*
  35. 第一个参数:队列
  36. 第二个参数:要执行的任务
  37. */
  38. dispatch_async(queue, ^{
  39. NSLog(@"download1----%@",[NSThread currentThread]);
  40. });
  41. dispatch_async(queue, ^{
  42. NSLog(@"download2----%@",[NSThread currentThread]);
  43. });
  44. dispatch_async(queue, ^{
  45. NSLog(@"download3----%@",[NSThread currentThread]);
  46. });
  47. NSLog(@"---end----");
  48. }
  49. //异步函数+串行队列:会开线程,开一条线程,队列中的任务是串行执行的
  50. -(void)asyncSerial
  51. {
  52. //1.创建队列
  53. dispatch_queue_t queue = dispatch_queue_create("download", DISPATCH_QUEUE_SERIAL);
  54. //2.封装操作
  55. dispatch_async(queue, ^{
  56. NSLog(@"download1----%@",[NSThread currentThread]);
  57. });
  58. dispatch_async(queue, ^{
  59. NSLog(@"download2----%@",[NSThread currentThread]);
  60. });
  61. dispatch_async(queue, ^{
  62. NSLog(@"download3----%@",[NSThread currentThread]);
  63. });
  64. }
  65. //同步函数+并发队列:不会开线程,任务是串行执行的
  66. -(void)syncConcurrent
  67. {
  68. //1.创建队列
  69. dispatch_queue_t queue = dispatch_queue_create("com.www.download", DISPATCH_QUEUE_CONCURRENT);
  70. NSLog(@"---start---");
  71. //2.封装任务
  72. dispatch_sync(queue, ^{
  73. NSLog(@"download1----%@",[NSThread currentThread]);
  74. });
  75. dispatch_sync(queue, ^{
  76. NSLog(@"download2----%@",[NSThread currentThread]);
  77. });
  78. dispatch_sync(queue, ^{
  79. NSLog(@"download3----%@",[NSThread currentThread]);
  80. });
  81. NSLog(@"---end---");
  82. }
  83. //同步函数+串行队列:不会开线程,任务是串行执行的
  84. -(void)syncSerial
  85. {
  86. //1.创建队列
  87. dispatch_queue_t queue = dispatch_queue_create("com.www.download", DISPATCH_QUEUE_SERIAL);
  88. //2.封装任务
  89. dispatch_sync(queue, ^{
  90. NSLog(@"download1----%@",[NSThread currentThread]);
  91. });
  92. dispatch_sync(queue, ^{
  93. NSLog(@"download2----%@",[NSThread currentThread]);
  94. });
  95. dispatch_sync(queue, ^{
  96. NSLog(@"download3----%@",[NSThread currentThread]);
  97. });
  98. }
  99. //异步函数+主队列:所有任务都在主线程中执行,不会开线程
  100. -(void)asyncMain
  101. {
  102. //1.获得主队列
  103. dispatch_queue_t queue = dispatch_get_main_queue();
  104. //2.异步函数
  105. dispatch_async(queue, ^{
  106. NSLog(@"download1----%@",[NSThread currentThread]);
  107. });
  108. dispatch_async(queue, ^{
  109. NSLog(@"download2----%@",[NSThread currentThread]);
  110. });
  111. dispatch_async(queue, ^{
  112. NSLog(@"download3----%@",[NSThread currentThread]);
  113. });
  114. }
  115. //同步函数+主队列:死锁
  116. //注意:如果该方法在子线程中执行,那么所有的任务在主线程中执行,不会死锁
  117. -(void)syncMain
  118. {
  119. //1.获得主队列
  120. dispatch_queue_t queue = dispatch_get_main_queue();
  121. NSLog(@"start----");
  122. //2.同步函数
  123. //同步函数:立刻马上执行,如果我没有执行完毕,那么后面的也别想执行
  124. //异步函数:如果我没有执行完毕,那么后面的也可以执行
  125. dispatch_sync(queue, ^{
  126. NSLog(@"download1----%@",[NSThread currentThread]);
  127. });
  128. dispatch_sync(queue, ^{
  129. NSLog(@"download2----%@",[NSThread currentThread]);
  130. });
  131. dispatch_sync(queue, ^{
  132. NSLog(@"download3----%@",[NSThread currentThread]);
  133. });
  134. NSLog(@"end---");
  135. }
  136. @end

   


各种队列的执行效果

 注意:使用sync(同步)函数往当前串行队列中添加任务,会卡住当前的串行队列,造成死锁


GCD实现线程间通信(子线程耗时下载,主线程更新UI)

  • 从子线程回到主线程

dispatch_async(

       dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^{

        // 执行耗时的异步操作...

        dispatch_async(dispatch_get_main_queue(), ^{

         // 回到主线程,执行UI刷新操作

        });

});

  1. #import "ViewController.h"
  2. @interface ViewController ()
  3. @property (weak, nonatomic) IBOutlet UIImageView *imageView;
  4. @end
  5. @implementation ViewController
  6. -(void)touchesBegan:(NSSet<UITouch *> *)touches withEvent:(UIEvent *)event
  7. {
  8. //1.创建子线程下载图片
  9. //DISPATCH_QUEUE_PRIORITY_DEFAULT 0
  10. dispatch_async(dispatch_get_global_queue(0, 0), ^{
  11. //1.1 确定url
  12. NSURL *url = [NSURL URLWithString:@"http://a.hiphotos.baidu.com/zhidao/wh%3D450%2C600/sign=da0ec79c738da9774e7a8e2f8561d42f/c83d70cf3bc79f3d6842e09fbaa1cd11738b29f9.jpg"];
  13. //1.2 下载二进制数据到本地
  14. NSData *imageData = [NSData dataWithContentsOfURL:url];
  15. //1.3 转换图片
  16. UIImage *image = [UIImage imageWithData:imageData];
  17. NSLog(@"download----%@",[NSThread currentThread]);
  18. //更新UI
  19. // dispatch_async(dispatch_get_main_queue(), ^{
  20. dispatch_sync(dispatch_get_main_queue(), ^{
  21. self.imageView.image = image;
  22. NSLog(@"UI----%@",[NSThread currentThread]);
  23. });
  24. });
  25. }
  26. @end

GCD常用函数

  • 延时执行

    1)调用NSObject的方法

  • [self performSelector:@selector(run) withObject:nil afterDelay:2.0];

    // 2秒后再调run方法

     2)使用GCD函数

  • dispatch_after(dispatch_time(DISPATCH_TIME_NOW, (int64_t)(2.0 * NSEC_PER_SEC)), dispatch_get_main_queue(), ^{

        // 2秒后执行这里的代码...

    });

      3)使用NSTimer

  • [NSTimer scheduledTimerWithTimeInterval:2.0 target:self selector:@selector(test) userInfo:nil repeats:NO];

  • 4)一次性代码

    1. //使用dispatch_once函数能保证某段代码在程序运行过程中只被执行1
    2. static dispatch_once_t onceToken;
    3. dispatch_once(&onceToken, ^{
    4. // 只执行1次的代码(这里面默认是线程安全的)
    5. });

    5)代码示例

  1. #import "ViewController.h"
  2. @interface ViewController ()
  3. @end
  4. @implementation ViewController
  5. -(void)touchesBegan:(NSSet<UITouch *> *)touches withEvent:(UIEvent *)event
  6. {
  7. [self once];
  8. }
  9. //延迟执行
  10. -(void)delay
  11. {
  12. NSLog(@"start-----");
  13. //1. 延迟执行的第一种方法
  14. //[self performSelector:@selector(task) withObject:nil afterDelay:2.0];
  15. //2.延迟执行的第二种方法
  16. //[NSTimer scheduledTimerWithTimeInterval:2.0 target:self selector:@selector(task) userInfo:nil repeats:YES];
  17. //3.GCD
  18. // dispatch_queue_t queue = dispatch_get_main_queue();
  19. dispatch_queue_t queue = dispatch_get_global_queue(0, 0);
  20. /*
  21. 第一个参数:DISPATCH_TIME_NOW 从现在开始计算时间
  22. 第二个参数:延迟的时间 2.0 GCD时间单位:纳秒
  23. 第三个参数:队列
  24. */
  25. dispatch_after(dispatch_time(DISPATCH_TIME_NOW, (int64_t)(2.0 * NSEC_PER_SEC)), queue, ^{
  26. NSLog(@"GCD----%@",[NSThread currentThread]);
  27. });
  28. }
  29. //一次性代码
  30. //不能放在懒加载中的,应用场景:单例模式
  31. -(void)once
  32. {
  33. static dispatch_once_t onceToken;
  34. dispatch_once(&onceToken, ^{
  35. NSLog(@"---once----");
  36. });
  37. }
  38. -(void)task
  39. {
  40. NSLog(@"task----%@",[NSThread currentThread]);
  41. }
  42. @end

GCD栅栏函数

  • GCD中还有个用来执行任务的函数:

       dispatch_barrier_async(dispatch_queue_t queue, dispatch_block_t block);

       在前面的任务执行结束后它才执行,而且它后面的任务等它执行完成之后才会执行

  • 这个queue不能是全局的并发队列
  1. #import "ViewController.h"
  2. @interface ViewController ()
  3. @end
  4. @implementation ViewController
  5. -(void)touchesBegan:(NSSet<UITouch *> *)touches withEvent:(UIEvent *)event
  6. {
  7. //0.获得全局并发队列
  8. //栅栏函数不能使用全局并发队列,只能使用自己创建的并发队列
  9. //dispatch_queue_t queue = dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0);
  10. dispatch_queue_t queue = dispatch_queue_create("download", DISPATCH_QUEUE_CONCURRENT);
  11. //1.异步函数
  12. dispatch_async(queue, ^{
  13. for (NSInteger i = 0; i<100; i++) {
  14. NSLog(@"download1-%zd-%@",i,[NSThread currentThread]);
  15. }
  16. });
  17. dispatch_async(queue, ^{
  18. for (NSInteger i = 0; i<100; i++) {
  19. NSLog(@"download2-%zd-%@",i,[NSThread currentThread]);
  20. }
  21. });
  22. //栅栏函数
  23. dispatch_barrier_async(queue, ^{
  24. NSLog(@"+++++++++++++++++++++++++++++");
  25. });
  26. dispatch_async(queue, ^{
  27. for (NSInteger i = 0; i<100; i++) {
  28. NSLog(@"download3-%zd-%@",i,[NSThread currentThread]);
  29. }
  30. });
  31. dispatch_async(queue, ^{
  32. for (NSInteger i = 0; i<100; i++) {
  33. NSLog(@"download4-%zd-%@",i,[NSThread currentThread]);
  34. }
  35. });
  36. }
  37. @end

GCD快速迭代

  • 使用dispatch_apply函数能进行快速迭代遍历
  1. dispatch_apply(10, dispatch_get_global_queue(0, 0), ^(size_t index){
  2.     // 执行10次代码,index顺序不确定
  3. });

剪切文件代码示例:

  1. #import "ViewController.h"
  2. @interface ViewController ()
  3. @end
  4. @implementation ViewController
  5. -(void)touchesBegan:(NSSet<UITouch *> *)touches withEvent:(UIEvent *)event
  6. {
  7. [self moveFileWithGCD];
  8. }
  9. -(void)forDemo
  10. {
  11. //同步,在主线程串行
  12. for (NSInteger i = 0; i<10; i++) {
  13. NSLog(@"%zd---%@",i,[NSThread currentThread]);
  14. }
  15. }
  16. //开子线程和主线程一起完成遍历任务,任务的执行时并发的
  17. -(void)applyDemo
  18. {
  19. /*
  20. 第一个参数:遍历的次数
  21. 第二个参数:队列(并发队列)
  22. 第三个参数:index 索引
  23. */
  24. dispatch_apply(10, dispatch_get_global_queue(0, 0), ^(size_t index) {
  25. NSLog(@"%zd---%@",index,[NSThread currentThread]);
  26. });
  27. }
  28. //使用for循环
  29. -(void)moveFile
  30. {
  31. //1.拿到文件路径
  32. NSString *from = @"/Users/Alan/Desktop/from";
  33. //2.获得目标文件路径
  34. NSString *to = @"/Users/Alan/Desktop/to";
  35. //3.得到目录下面的所有文件
  36. NSArray *subPaths = [[NSFileManager defaultManager] subpathsAtPath:from];
  37. NSLog(@"%@",subPaths);
  38. //4.遍历所有文件,然后执行剪切操作
  39. NSInteger count = subPaths.count;
  40. for (NSInteger i = 0; i< count; i++) {
  41. //4.1 拼接文件的全路径
  42. // NSString *fullPath = [from stringByAppendingString:subPaths[i]];
  43. //在拼接的时候会自动添加/
  44. NSString *fullPath = [from stringByAppendingPathComponent:subPaths[i]];
  45. NSString *toFullPath = [to stringByAppendingPathComponent:subPaths[i]];
  46. NSLog(@"%@",fullPath);
  47. //4.2 执行剪切操作
  48. /*
  49. 第一个参数:要剪切的文件在哪里
  50. 第二个参数:文件应该被存到哪个位置
  51. */
  52. [[NSFileManager defaultManager]moveItemAtPath:fullPath toPath:toFullPath error:nil];
  53. NSLog(@"%@---%@--%@",fullPath,toFullPath,[NSThread currentThread]);
  54. }
  55. }
  56. -(void)moveFileWithGCD
  57. {
  58. //1.拿到文件路径
  59. NSString *from = @"/Users/Alan/Desktop/from";
  60. //2.获得目标文件路径
  61. NSString *to = @"/Users/Alan/Desktop/to";
  62. //3.得到目录下面的所有文件
  63. NSArray *subPaths = [[NSFileManager defaultManager] subpathsAtPath:from];
  64. NSLog(@"%@",subPaths);
  65. //4.遍历所有文件,然后执行剪切操作
  66. NSInteger count = subPaths.count;
  67. dispatch_apply(count, dispatch_get_global_queue(0, 0), ^(size_t i) {
  68. //4.1 拼接文件的全路径
  69. // NSString *fullPath = [from stringByAppendingString:subPaths[i]];
  70. //在拼接的时候会自动添加/
  71. NSString *fullPath = [from stringByAppendingPathComponent:subPaths[i]];
  72. NSString *toFullPath = [to stringByAppendingPathComponent:subPaths[i]];
  73. NSLog(@"%@",fullPath);
  74. //4.2 执行剪切操作
  75. /*
  76. 第一个参数:要剪切的文件在哪里
  77. 第二个参数:文件应该被存到哪个位置
  78. */
  79. [[NSFileManager defaultManager]moveItemAtPath:fullPath toPath:toFullPath error:nil];
  80. NSLog(@"%@---%@--%@",fullPath,toFullPath,[NSThread currentThread]);
  81. });
  82. }
  83. @end

GCD队列组

  • 队列组使用情况

     1)分别异步执行多个耗时的操作

     2)等多个异步操作都执行完毕后,再回到主线程执行操作

    3)拦截通知,当队列组中所有的任务都执行完毕的时候回进入到下面的方法,异步的,不会阻塞线程

  1. dispatch_group_t group =  dispatch_group_create();
  2. dispatch_group_async(group, dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^{
  3.     // 执行1个耗时的异步操作
  4. });
  5. dispatch_group_async(group, dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^{
  6.     // 执行1个耗时的异步操作
  7. });
  8. dispatch_group_notify(group, dispatch_get_main_queue(), ^{
  9.     // 等前面的异步操作都执行完毕后,回到主线程...
  10. });

 下载两张图片合并成一张代码示例:

  1. #import "ViewController.h"
  2. @interface ViewController ()
  3. /** 图片1 */
  4. @property (nonatomic, strong) UIImage *image1;
  5. /**2 */
  6. @property (nonatomic, strong) UIImage *image2;
  7. @property (weak, nonatomic) IBOutlet UIImageView *imageView;
  8. @end
  9. @implementation ViewController
  10. #pragma mark ----------------------
  11. #pragma mark Events
  12. -(void)touchesBegan:(NSSet<UITouch *> *)touches withEvent:(UIEvent *)event
  13. {
  14. [self test];
  15. }
  16. #pragma mark ----------------------
  17. #pragma mark Methods
  18. -(void)group1
  19. {
  20. //1.创建队列
  21. dispatch_queue_t queue =dispatch_get_global_queue(0, 0);
  22. //2.创建队列组
  23. dispatch_group_t group = dispatch_group_create();
  24. //3.异步函数
  25. /*
  26. 1)封装任务
  27. 2)把任务添加到队列中
  28. dispatch_async(queue, ^{
  29. NSLog(@"1----%@",[NSThread currentThread]);
  30. });
  31. */
  32. /*
  33. 1)封装任务
  34. 2)把任务添加到队列中
  35. 3)会监听任务的执行情况,通知group
  36. */
  37. dispatch_group_async(group, queue, ^{
  38. NSLog(@"1----%@",[NSThread currentThread]);
  39. });
  40. dispatch_group_async(group, queue, ^{
  41. NSLog(@"2----%@",[NSThread currentThread]);
  42. });
  43. dispatch_group_async(group, queue, ^{
  44. NSLog(@"3----%@",[NSThread currentThread]);
  45. });
  46. //拦截通知,当队列组中所有的任务都执行完毕的时候回进入到下面的方法,异步的,不会阻塞线程
  47. dispatch_group_notify(group, queue, ^{
  48. NSLog(@"-------dispatch_group_notify-------");
  49. });
  50. NSLog(@"----end----");
  51. }
  52. -(void)group2
  53. {
  54. //1.创建队列
  55. dispatch_queue_t queue =dispatch_get_global_queue(0, 0);
  56. //2.创建队列组
  57. dispatch_group_t group = dispatch_group_create();
  58. //3.在该方法后面的异步任务会被纳入到队列组的监听范围,进入群组
  59. //dispatch_group_enter|dispatch_group_leave 必须要配对使用
  60. dispatch_group_enter(group);
  61. dispatch_async(queue, ^{
  62. NSLog(@"1----%@",[NSThread currentThread]);
  63. //离开群组
  64. dispatch_group_leave(group);
  65. });
  66. dispatch_group_enter(group);
  67. dispatch_async(queue, ^{
  68. NSLog(@"2----%@",[NSThread currentThread]);
  69. //离开群组
  70. dispatch_group_leave(group);
  71. });
  72. //拦截通知
  73. //问题?该方法是阻塞的吗? 内部本身是异步的
  74. // dispatch_group_notify(group, queue, ^{
  75. // NSLog(@"-------dispatch_group_notify-------");
  76. // });
  77. //等待.死等. 直到队列组中所有的任务都执行完毕之后才能执行
  78. //阻塞的,会阻塞线程
  79. dispatch_group_wait(group, DISPATCH_TIME_FOREVER);
  80. NSLog(@"----end----");
  81. }
  82. -(void)group3
  83. {
  84. /*
  85. 1.下载图片1 开子线程
  86. 2.下载图片2 开子线程
  87. 3.合成图片并显示图片 开子线程
  88. */
  89. //-1.获得队列组
  90. dispatch_group_t group = dispatch_group_create();
  91. //0.获得并发队列
  92. dispatch_queue_t queue = dispatch_get_global_queue(0, 0);
  93. // 1.下载图片1 开子线程
  94. dispatch_group_async(group, queue,^{
  95. NSLog(@"download1---%@",[NSThread currentThread]);
  96. //1.1 确定url
  97. NSURL *url = [NSURL URLWithString:@"http://www.qbaobei.com/tuku/images/13.jpg"];
  98. //1.2 下载二进制数据
  99. NSData *imageData = [NSData dataWithContentsOfURL:url];
  100. //1.3 转换图片
  101. self.image1 = [UIImage imageWithData:imageData];
  102. });
  103. // 2.下载图片2 开子线程
  104. dispatch_group_async(group, queue,^{
  105. NSLog(@"download2---%@",[NSThread currentThread]);
  106. //2.1 确定url
  107. NSURL *url = [NSURL URLWithString:@"http://pic1a.nipic.com/2008-09-19/2008919134941443_2.jpg"];
  108. //2.2 下载二进制数据
  109. NSData *imageData = [NSData dataWithContentsOfURL:url];
  110. //2.3 转换图片
  111. self.image2 = [UIImage imageWithData:imageData];
  112. });
  113. //3.合并图片
  114. //主线程中执行
  115. dispatch_group_notify(group, dispatch_get_main_queue(), ^{
  116. NSLog(@"combie---%@",[NSThread currentThread]);
  117. //3.1 创建图形上下文
  118. UIGraphicsBeginImageContext(CGSizeMake(200, 200));
  119. //3.2 画图1
  120. [self.image1 drawInRect:CGRectMake(0, 0, 200, 100)];
  121. self.image1 = nil;
  122. //3.3 画图2
  123. [self.image2 drawInRect:CGRectMake(0, 100, 200, 100)];
  124. self.image2 = nil;
  125. //3.4 根据上下文得到一张图片
  126. UIImage *image = UIGraphicsGetImageFromCurrentImageContext();
  127. //3.5 关闭上下文
  128. UIGraphicsEndImageContext();
  129. //3.6 更新UI
  130. // dispatch_async(dispatch_get_main_queue(), ^{
  131. NSLog(@"UI----%@",[NSThread currentThread]);
  132. self.imageView.image = image;
  133. // });
  134. });
  135. // dispatch_release(group)
  136. }
  137. -(void)test
  138. {
  139. // dispatch_async(<#dispatch_queue_t queue#>, <#^(void)block#>)
  140. //区别:封装任务的方法(block--函数)
  141. /*
  142. 第一个参数:队列
  143. 第二个参数:参数
  144. 第三个参数:要调用的函数的名称
  145. */
  146. dispatch_async_f(dispatch_get_global_queue(0, 0), NULL, task);
  147. dispatch_async_f(dispatch_get_global_queue(0, 0), NULL, task);
  148. dispatch_async_f(dispatch_get_global_queue(0, 0), NULL, task);
  149. }
  150. void task(void *param)
  151. {
  152. NSLog(@"%s---%@",__func__,[NSThread currentThread]);
  153. }
  154. @end

GCD单例模式

  • 单例模式的作用

   1)可以保证在程序运行过程,一个类只有一个实例,而且该实例易于供外界访问

   2)从而方便地控制了实例个数,并节约系统资源

  • 单例模式的使用场合
  • 在整个应用程序中,共享一份资源(这份资源只需要创建初始化1次)
  • ARC中,单例模式的实现

    1)在.m中保留一个全局的static的实例

static id _instance;

     2)重写allocWithZone:方法,在这里创建唯一的实例(注意线程安全)

  1. + (instancetype)allocWithZone:(struct _NSZone *)zone
  2. {
  3.     static dispatch_once_t onceToken;
  4.     dispatch_once(&onceToken, ^{
  5.         _instance = [super allocWithZone:zone];
  6.     });
  7.     return _instance;
  8. }
  • 提供1个类方法让外界访问唯一的实例
  1. + (instancetype)sharedInstance
  2. {
  3.     static dispatch_once_t onceToken;
  4.     dispatch_once(&onceToken, ^{
  5.         _instance = [[self alloc] init];
  6.     });
  7.     return _instance;
  8. }

 

  • 实现copyWithZone:方法
  1. - (id)copyWithZone:(struct _NSZone *)zone
  2. {
  3.     return _instance;
  4. }

 具体单例代码:

AlanTool.h

  1. #import <Foundation/Foundation.h>
  2. @interface AlanTool : NSObject<NSCopying, NSMutableCopying>
  3. //类方法
  4. //1.方便访问
  5. //2.标明身份
  6. //3.注意:share+类名|default + 类名 | share | default | 类名
  7. +(instancetype)shareTool;
  8. @end

AlanTool.m

  1. #import "AlanTool.m"
  2. @implementation AlanTool
  3. //0.提供全局变量
  4. static AlanTool *_instance;
  5. //1.alloc-->allocWithZone
  6. +(instancetype)allocWithZone:(struct _NSZone *)zone
  7. {
  8. //加互斥锁解决多线程访问安全问题
  9. // @synchronized(self) {
  10. // if (_instance == nil) {
  11. // _instance = [super allocWithZone:zone];
  12. // }
  13. // }
  14. //本身就是线程安全的
  15. static dispatch_once_t onceToken;
  16. dispatch_once(&onceToken, ^{
  17. _instance = [super allocWithZone:zone];
  18. });
  19. return _instance;
  20. }
  21. //2.提供类方法
  22. +(instancetype)shareTool
  23. {
  24. //1
  25. //return [[self alloc]init];
  26. //2
  27. static dispatch_once_t onceToken;
  28. dispatch_once(&onceToken, ^{
  29. _instance = [super allocWithZone:zone];
  30. });
  31. return _instance;
  32. }
  33. //3.严谨
  34. -(id)copyWithZone:(NSZone *)zone
  35. {
  36. return _instance;
  37. }
  38. -(id)mutableCopyWithZone:(NSZone *)zone
  39. {
  40. return _instance;
  41. }
  42. #if __has_feature(objc_arc)
  43. //条件满足 ARC
  44. #else
  45. // MRC
  46. -(void)release
  47. {
  48. }
  49. -(instancetype)retain
  50. {
  51. return _instance;
  52. }
  53. //习惯
  54. -(NSUInteger)retainCount
  55. {
  56. return MAXFLOAT;
  57. }
  58. #endif
  59. @end

通过宏实现GCD单例模式

  1. #define SingleH(name) +(instancetype)share##name;
  2. #if __has_feature(objc_arc)
  3. //条件满足 ARC
  4. #define SingleM(name) static id _instance;\
  5. +(instancetype)allocWithZone:(struct _NSZone *)zone\
  6. {\
  7. static dispatch_once_t onceToken;\
  8. dispatch_once(&onceToken, ^{\
  9. _instance = [super allocWithZone:zone];\
  10. });\
  11. \
  12. return _instance;\
  13. }\
  14. \
  15. +(instancetype)share##name\
  16. {\
  17. return [[self alloc]init];\
  18. }\
  19. \
  20. -(id)copyWithZone:(NSZone *)zone\
  21. {\
  22. return _instance;\
  23. }\
  24. \
  25. -(id)mutableCopyWithZone:(NSZone *)zone\
  26. {\
  27. return _instance;\
  28. }
  29. #else
  30. //MRC
  31. #define SingleM(name) static id _instance;\
  32. +(instancetype)allocWithZone:(struct _NSZone *)zone\
  33. {\
  34. static dispatch_once_t onceToken;\
  35. dispatch_once(&onceToken, ^{\
  36. _instance = [super allocWithZone:zone];\
  37. });\
  38. \
  39. return _instance;\
  40. }\
  41. \
  42. +(instancetype)share##name\
  43. {\
  44. return [[self alloc]init];\
  45. }\
  46. \
  47. -(id)copyWithZone:(NSZone *)zone\
  48. {\
  49. return _instance;\
  50. }\
  51. \
  52. -(id)mutableCopyWithZone:(NSZone *)zone\
  53. {\
  54. return _instance;\
  55. }\
  56. -(oneway void)release\
  57. {\
  58. }\
  59. \
  60. -(instancetype)retain\
  61. {\
  62. return _instance;\
  63. }\
  64. \
  65. -(NSUInteger)retainCount\
  66. {\
  67. return MAXFLOAT;\
  68. }
  69. #endif

 

声明:本文内容由网友自发贡献,不代表【wpsshop博客】立场,版权归原作者所有,本站不承担相应法律责任。如您发现有侵权的内容,请联系我们。转载请注明出处:https://www.wpsshop.cn/w/盐析白兔/article/detail/691468
推荐阅读
相关标签
  

闽ICP备14008679号