Grand Central Dispatch

Grand Central Dispatch的理念就是你有一系列的操作队列,我们放置一个block的队列,这些block会出队列,然后在另外一个线程里面执行。

  但是也有主队列,主队列就是UIKit的事情发生的地方,所有的绘图工作,这个队列我们要保证不放任何与UI无关的东西在上面,因为我们始终想要这个队列处在无压力处理手势或其他类似的事情状态。所以我们搞多线程就是把这些需要长时间运行的block放到队列里面,让它们在另外的线程里面运行,然后那些线程再回主线程更新UI。这样我们就能在另外的线程里面做那些block的事情,比如访问网络或一些很费资源的事情。

  在这个API里面有什么重要的函数?
  

  1. dispatch_queue_t dispatch_queue_create(const char *label, NULL); // serial queue


  这创建一个队列,一个将要放block进去的队列。
  

  1. typedef void (^dispatch_block_t)(void);
  2.   void dispatch_async(dispatch_queue_t queue, dispatch_block_t block);


  将block放到队列里,然后在未来某个不确定的时间,会有人把这个block移出队列到另外一个线程为我们执行。

  有两个有趣的方法去得到当前的队列,有时会有人用block调用你,请求你去做些事情,然后你想要在另外的线程里面做一部分,所以你会想要知道这个调用的人所在的队列。因为你可能想要在一个线程里面执行一些事情之后发送消息回这个调用你的队列。
  

  1. dispatch_queue_t dispatch_get_current_queue();
  2.   void dispatch_queue_retain(dispatch_queue_t); // keep it in the heap until dispatch_release


  但更重要的是想要得到主队列,就是UIKit的队列,这是要放置任何会涉及UI的代码的地方,如果你发布到除主线程以外的其他线程的队列运行UIKit的代码,会出现问题。
 

  1.  dispatch_queue_t dispatch_get_main_queue();


  如果你在另外的线程里面做点事情,然后你需要做些关于UIKit的东西,你可以放一个block来传回到主线程里面执行。

  这看起来是什么样子呢?假设有个方法,它去访问网络然后取回一些内容,比如图片的URL,然后我利用这个数据创建了一个UIImage,然后我把它设置到一个image view里,我放入一个scrollView,然后会显示的。这个URL的数据内容可能会花费这个方法很长一段时间去取,不想让这段代码在主队列中运行,因为这样的话,在viewWillAppear的过程中UI会完全没有反应。所以仅仅需要创建一个队列,一个下载队列,我会调用它。dispatch_queue_create的第一个参数是const char *,这是纯C API,不能是NSString,你会在debugger里面看到那个线程,这个参数就是做这个用。这个NULL就是标识这是否是一个连续的队列或者是并发的队列,NULL意味着连续队列。
  

  1. - (void)viewWillAppear:(BOOL)animated
  2.   {
  3.   dispatch_queue_t downloadQueue = dispatch_queue_create(“image downloader”, NULL);
  4.   dispatch_async(downloadQueue, ^{
  5.   NSData *imageData = [NSData dataWithContentsOfURL:networkURL];
  6.   dispatch_async(dispatch_get_main_queue(), ^{
  7.   UIImage *image = [UIImage imageWithData:imageData];
  8.   self.imageView.image = image;
  9.   self.imageView.frame = CGRectMake(0, 0, image.size.width, image.size.height);
  10.   self.scrollView.contentSize = image.size;
  11.   });
  12.   });
  13.   dispatch_release(downloadQueue);
  14.   }


  创建了这个队列,然后是dispatch_async,里面是想要在另外一个线程里面做的block,有几个难点要注意:一,UIKit的调用只能发生在主线程里面,移动UIKit相关的代码回主队列,如果有些东西需要回到另外的队列上去执行,只要把它们发布到另外的队列上就行,按时间线性执行就好,被执行的东西会在队列和队列之间来回传递,只要保证它们在正确的队列上执行就可以了。正确的队列就是,关于UI的东西都放在主线程上,别的东西都要放在其他线程上。二,关于download线程的内存管理问题,这些线程不是对象,而是C语言代码,所以必须对downloadQueue调用dispatch_release方法,意思是只要队列里不再有block了,就可以release。

  downloadQueue是一个独立的线程,并不会锁住主线程。一旦进行了dispatch_async,主线程就会保持执行,直到我向它请求执行一些代码,这样主线程就不会锁。当我想执行一些imageView设置的代码时,就会把这个block放到主线程执行,如果此时主线程正在处理手势,当这些手势执行完,它会询问有block要执行吗?真的有,这样就会显示图片。先把它们加到线程队列上,然后在它们准备执行时,再把它们出队。

  一旦把某个东西放到队列上,就不能剔除它。而且一旦队列上的某个进程开始执行了,不能打断它。

原文地址:https://www.cnblogs.com/baozou/p/3317756.html