IOS GCD详解

IOS GCD
一:Grand Central Dispatch 简称(GCD)是苹果公司开发的技术,以优化的应用程序支持多核心处理器和其他的对称多处理系统的系统。这建立在任务并行执行的线程池模式的基础上的。它首次发布在Mac OS X 10.6 ,iOS 4及以上也可用。GCD是异步执行任务的技术之一,一般将应用程序中记叙的线程管理用的代码在系统级中是实现。
开发者只需要定义想要执行的任务并追加到适当的Dispatch Queue中,GCD就能生成必要的线程并计划执行任务。
二:多线程编程
由于使用多线程的程序可以在某个线程和其他线程之间反复多次进行上下文切换,因此看上去就好像一个CPU核能够并行的执行多个线程一样,而且在具有多个CPU核的情况下,就不是“看上去像”了,而是真的提供了多个CPU核并行执行任务的多个线程的技术。
多线程编程容易发生各种编程问题:比如多个线程更新相同的资源会导致数据的不一致(数据竞争)、停止等待事件的线程会导致多个线程相互持续等待(死锁)、使用太多线程会消耗大量的内存资源等等。
尽管会有问题,但是为什么还要用呢?
在应用程序启动时,通过最先执行的线程,即主线程来描绘用户界面、处理用户触摸事件等,但是如果在该主线程中进行长时间的处理,就会妨碍主线程中被称为RunLoop的主循环的执行,从而导致不能跟新用户界面,应用程序的画面长时间停滞等问题。
三:GCD的工作原理是:让程序平行排队来执行特定任务,根据可用的处理资源,安排他们在任何可用的处理器核心上执行任务。
一个任务可以是一个函数(function)或者是一个block。 GCD的底层依然是用线程实现,不过这样可以让程序员不用关注实现的细节。
GCD中的FIFO队列称为dispatch queue,它可以保证先进来的任务先得到执行
dispatch queue分为下面三种:
Serial         
    又 称为private dispatch queues,同时只执行一个任务。Serial queue通常用于同步访问特定的资源或数据。当你创建多个Serial queue时,Serial queue与Serial queue之间是并发执行的,即它们各自是同步执行的。
Concurrent    
又称为global dispatch queue,可以并发地执行多个任务,但是执行完成的顺序是随机的。
Main dispatch queue    
它是全局可用的serial queue,它是在应用程序主线程上执行任务的。


二.先讲一些常用的方法(后面再深层次详解)

1.dispatch_async
为了避免界面在处理耗时的操作时卡死,比如读取网络数据,IO,数据库读写等,我们会在另外一个线程中处理这些操作,然后通知主线程更新界面。
用GCD实现这个流程的操作比NSThread  NSOperation的方法都要简单。代码框架结构如下:
dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^{
    // 耗时的操作
    dispatch_async(dispatch_get_main_queue(), ^{
        // 更新界面
    });
});
如果这样还不清晰的话,那我们还是用上两篇博客中的下载图片为例子,代码如下:
    dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^{
        NSURL * url = [NSURL URLWithString:@"http://avatar.csdn.net/2/C/D/1_totogo2010.jpg"];
        NSData * data = [[NSData alloc]initWithContentsOfURL:url];
        UIImage *image = [[UIImage alloc]initWithData:data];
        if (data != nil) {
            dispatch_async(dispatch_get_main_queue(), ^{
                self.imageView.image = image;
             });
        }
    });

是不是代码比NSThread  NSOperation简洁很多,而且GCD会自动根据任务在多核处理器上分配资源,优化程序。
系统给每一个应用程序提供了三个concurrent dispatch queues。这三个并发调度队列是全局的,它们只有优先级的不同。因为是全局的,我们不需要去创建。我们只需要通过使用函数dispath_get_global_queue去得到队列,如下:
dispatch_queue_t    globalQ = dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0);  

这里也用到了系统默认就有一个串行队列main_queue
dispatch_queue_t mainQ = dispatch_get_main_queue();  

虽然dispatch queue是引用计数的对象,但是以上两个都是全局的队列,不用retain或release。
2.dispatch_group_async
dispatch_group_async可以实现监听一组任务是否完成,完成后得到通知执行其他的操作。这个方法很有用,比如你执行三个下载任务,当三个任务都下载完成后你才通知界面说完成的了。下面是一段例子代码:

    dispatch_queue_t queue = dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0);
    dispatch_group_t group = dispatch_group_create();
    dispatch_group_async(group, queue, ^{
        [NSThread sleepForTimeInterval:1];
        NSLog(@"group1");
    });
    dispatch_group_async(group, queue, ^{
        [NSThread sleepForTimeInterval:2];
        NSLog(@"group2");
    });
    dispatch_group_async(group, queue, ^{
        [NSThread sleepForTimeInterval:3];
        NSLog(@"group3");
    });
    dispatch_group_notify(group, dispatch_get_main_queue(), ^{
        NSLog(@"updateUi");
    });
    dispatch_release(group);
dispatch_group_async是异步的方法,运行后可以看到打印结果:

2012-09-25 16:04:16.737 gcdTest[43328:11303] group1
2012-09-25 16:04:17.738 gcdTest[43328:12a1b] group2
2012-09-25 16:04:18.738 gcdTest[43328:13003] group3
2012-09-25 16:04:18.739 gcdTest[43328:f803] updateUi
每个一秒打印一个,当第三个任务执行后,upadteUi被打印。

3.dispatch_barrier_async
dispatch_barrier_async是在前面的任务执行结束后它才执行,而且它后面的任务等它执行完成之后才会执行
例子代码如下:
    dispatch_queue_t queue = dispatch_queue_create("gcdtest.rongfzh.yc", DISPATCH_QUEUE_CONCURRENT);
    dispatch_async(queue, ^{
        [NSThread sleepForTimeInterval:2];
        NSLog(@"dispatch_async1");
    });
    dispatch_async(queue, ^{
        [NSThread sleepForTimeInterval:4];
        NSLog(@"dispatch_async2");
    });
    dispatch_barrier_async(queue, ^{
        NSLog(@"dispatch_barrier_async");
        [NSThread sleepForTimeInterval:4];

    });
    dispatch_async(queue, ^{
        [NSThread sleepForTimeInterval:1];
        NSLog(@"dispatch_async3");
    });

打印结果:

2012-09-25 16:20:33.967 gcdTest[45547:11203] dispatch_async1
2012-09-25 16:20:35.967 gcdTest[45547:11303] dispatch_async2
2012-09-25 16:20:35.967 gcdTest[45547:11303] dispatch_barrier_async
2012-09-25 16:20:40.970 gcdTest[45547:11303] dispatch_async3
请注意执行的时间,可以看到执行的顺序如上所述。
4、dispatch_apply

执行某个代码片段N次。
dispatch_apply(5, globalQ, ^(size_t index) {
    // 执行5次
});




三、深层次的讲解GCD 的 API
1.Dispatch Queue
开发者要做的只是定义想要执行的任务并追加到适当的DispatchQueue中。
在Block中定义想要执行的任务,然后追加到Dispatch Queue中
Dispatch Queue是执行处理的等待队列,通过dispatch_async等API,在Block语法中记叙想要执行的处理并将其追加到Dispatch Queue中,Dispatch Queue按照追加的顺序(FIFO)执行处理。
另外,在执行处理时存在两种Dispatch Queue:
Dispatch Queue的种类
 说明
 
Serial Dispatch Queue
 等待现在执行中处理结束
 
Concurrent Dispatch Queue
 不等待现在执行中处理结束

解释说明一下:
(1)         Serial Dispatch Queue:就是要等待现在执行中处理结束后才可以进行下一个任务的执行处理,假如现在有blk1,blk2,blk3,在Serial Dispatch Queue中,那么同时执行处理数只能是一个,而且按按添加顺序FIFO进行处理,即先执行blk1,执行结束后再执行blk2,执行结束再进行blk3 的执行。
(2)         Concurrent Dispatch Queue:就是一个线程的执行不等待现在(当前)执行中的任务处理结束就可以开始另一个任务的执行处理。同样假如有blk1,blk2,blk3在 Concurrent Dispatch Queue中,那么首先执行blk1,不管blk1是否执行处理结束,都开始执行后面的blk2,不管blk2是否执行结束,都开始执行后面的blk2。
这样虽然不用等待处理结束,可以并行执行多个任务处理,但是并行处理数取决于当前系统的状态,有它决定Concurrent Dispatch Queue中并行执行的处理数。所谓并行执行就是使用多个线程来同时执行多个处理任务(block中的执行任务)。
 

SerialDispatchQueue同时只能执行一个追加处理
ConcurrentDispatchQueue并行执行多个追加处理
虽然SerialDispatchQueue ConcurrentDispatchQueue受到系统资源的限制,但是用dispatch_queue_create可以生成任意多个Dispatch Queue
 当生成多个SerialDispatchQueue时,各个SerialDispatchQueue将并行执行,虽然一个SerialDispatchQueue同时只能执行一个追加处理,但是如果将处理分别追加到4个
Serial Dispatch Queue中,各个Serial Dispatch Queue执行一个,即为同时执行4个处理
但是生成Serial Dispatch Queue的个数受系统限制
  
为了避免多线程编程的问题之一---数据竞争,就可以使用Serial Dispatch Queue。
当想并行执行且不发生数据竞争等问题时就应该使用Concurrent Dispatch Queue。


//以下代码是两种生成Serial Dispatch Queue的方式  


   dispatch_queue_t mySerialDispatchQueue = dispatch_queue_create("cn.edu.scnu.mySerialDispatchQueue", NULL); 
    //        dispatch_queue_t mySerialDispatchQueue = dispatch_queue_create("cn.edu.scnu.mySerialDispatchQueue", DISPATCH_QUEUE_SERIAL);


dispatch_queue_create,该方法中
第一个参数指定SerialDispatchQueue的名称,DispatchQueue的名 称推荐使用应用程序ID之中逆序全程域名,
第二个参数指定为NULL(或者DISPATCH_QUEUE_SERIAL)时即表示生成的是Serial Dispatch Queue,指定为DISPATCH_QUEUE_CONCURRENT时即表示生成的是Concurrent Dispatch Queue

 
//以下代码生成ConcurrentDispatchQueue  
  

dispatch_queue_t myConcurrentDispatchQueue = dispatch_queue_create("cn.edu.scnu.myConcurrentDispatchQueue", DISPATCH_QUEUE_CONCURRENT); 
 
    dispatch_async(myConcurrentDispatchQueue, ^{ 
    

   NSLog(@"block on my ConcurrentDispatchQueue"); 


    });


2、MainDispatch Queue 和 Global Dispatch Queue

实际上不用特意生成DispatchQueue,系统也会提供几个给我们,就是Main DispatchQueue 和 Global Dispatch Queue
 Main Dispatch Queue就是主线程中执行的Dispatch Queue,因为主线程只有一个,所以Main DispatchQueue自然就是 Serial Dispatch Queue


//获取Main Dispatch Queue  
  

dispatch_queue_t mainDispatchQueue = dispatch_get_main_queue();

GlobalDispatch Queue是所有应用程序都能够使用的Concurrent Dispatch Queue,没有必要通过dispatch_queue_create方法逐个生成Concurrent Dispatch Queue,只要获

取GlobalDispatch Queue使用即可。


 Global Dispatch Queue有四个优先级:High Priority||Default Priority||Low Priority||Background Priority


 
 //获取高优先级的的Global Dispatch Queue
    /*
     DISPATCH_QUEUE_PRIORITY_HIGH      
     DISPATCH_QUEUE_PRIORITY_DEFAULT   
     DISPATCH_QUEUE_PRIORITY_LOW       
     DISPATCH_QUEUE_PRIORITY_BACKGROUND
     */
    dispatch_queue_t globalDispatchQueue = dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_HIGH, 0);
    //第一个参数指定Global Dispatch Queue的优先级,第二个参数指定为0

 
3、dispatch_set_target_queue
dispatch_queue_create函数生成的Dispatch Queue不管是Serial Dispatch Queue还是Concurrent Dispatch Queue,都是使用与默认优先级的Global Dispatch Queue相同执行优先级的线程
如果想变更生成的Dispatch Queue的执行优先级要使用dispatch_set_target_queue方法。


dispatch_queue_t mySerialDispatchQueue = dispatch_queue_create("cn.edu.scnu.mySerialDispatchQueue", NULL); 
  

dispatch_queue_t globalDispatchQueue = dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_HIGH, 0); 
  

dispatch_set_target_queue(mySerialDispatchQueue, globalDispatchQueue);


    //指定要变更执行优先级的dispatch queue为dispatch_set_target_queue方法的第一个参数,指定与要使用的执行优先级相同优先级的Global Dispatch Queue为第二个参数(目标)  


   //第一个参数不可以指定为系统提供的Main Dispatch Queue 和 Global Dispatch Queue

dispatch_queue_t mySerialDispatchQueue = dispatch_queue_create("cn.edu.scnu.mySerialDispatchQueue", NULL);
 

  dispatch_queue_t globalDispatchQueue = dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_HIGH, 0);
 

  dispatch_set_target_queue(mySerialDispatchQueue, globalDispatchQueue);


    //指定要变更执行优先级的dispatch queue为dispatch_set_target_queue方法的第一个参数,指定与要使用的执行优先级相同优先级的Global Dispatch Queue为第二个参数(目标)
 

  //第一个参数不可以指定为系统提供的Main Dispatch Queue 和 Global Dispatch Queue

 

4、dispatch_after
想在指定时间后执行处理的情况,可以使用 dispatch_after 方法来实现


double delayInSeconds = 2.0; 
 

dispatch_time_t popTime = dispatch_time(DISPATCH_TIME_NOW, (int64_t)(delayInSeconds * NSEC_PER_SEC)); 
 

dispatch_after(popTime, dispatch_get_main_queue(), ^(void){ 
   

   NSLog(@"waited  at least 2.0 seconds."); 
   });

 值得注意的是,dispatch_after方法并不是在指定时间后执行处理任务,而是在指定时间后追加处理到dispatch queue中,上面的代码在2秒后用dispatch_after方法追加

block到Main Dispatch Queue中,因为Main Dispatch Queue在主线程的RunLoop中执行,所以比如每个1/60秒执行的RunLoop中,Block最快在2秒后执行,最慢在2秒+1/60

秒后执行,而且在Main Dispatch Queue中又大量处理追加或者主线程的处理本身有延时时,这个时间会更长。



dispatch_after这个方法的第二个参数指定要追加的dispatch queue,第三个参数指定要执行处理的Block,第一个参数是指定时间用的dispatch_time_t类型的值,在使用
dispatch_after的时候,编译器会自动帮你生成这些代码,只需修改delayInSeconds就可以了。
 

5、Dispatch Group
在追加到dispatch queue中的多个处理全部结束后想执行结束处理任务,这种情况会经常出现。只使用一个Serial Dispatch Queue时,只要将想执行的全部处理都追加到该
Serial Dispatch Queue种并在最后追加结束处理就可以实现。但是在使用Concurrent Dispatch Queue时或者同时使用多个dispatch queue时,就会有些复杂了,在这种情况下
就应该使用Dispatch Group


dispatch_queue_t queue = dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_HIGH, 0); 
  

dispatch_group_t group = dispatch_group_create(); 
     


    dispatch_group_async(group, queue, ^{NSLog(@"blk1");}); 
  

dispatch_group_async(group, queue, ^{NSLog(@"blk2");}); 
 

  dispatch_group_async(group, queue, ^{NSLog(@"blk3");}); 
     


    dispatch_group_notify(group, dispatch_get_main_queue(), ^{ 
  

     NSLog(@"done"); 
    });

因为向 Global Dispatch Queue即Concurrent Dispatch Queue追加处理任务,多个线程并行执行,所以追加处理任务的执行顺序是不定的,执行时顺序会发生变化,但是主线程中执行结果输出done肯定是最后的。
  
下面稍微解释一下上面的那段代码,上面由3个输出任务的block组成一个dispatch group,并把这个dispatch group添加到dispatch queue中执行,当dispatch group中的
block任务执行完毕后,dispatch_group_notify方法就会被执行到,所以它的第一个参数是group,表示其被监视。在追加到dispatch group中的全部执行处理任务执行结束后,
将第三个参数中的block任务添加到第二个参数的dispatch queue中执行,注意此时dispatch group中的所以执行任务已经执行结束了。

另外,在dispatch group中也可以使用 dispatch_group_wait方法仅等待全部处理执行结束。


dispatch_queue_t queue = dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_HIGH, 0); 
  

dispatch_group_t group = dispatch_group_create(); 
     
 

  dispatch_group_async(group, queue, ^{NSLog(@"blk1");}); 


    dispatch_group_async(group, queue, ^{NSLog(@"blk2");}); 
  

dispatch_group_async(group, queue, ^{NSLog(@"blk3");}); 
     
  

dispatch_group_wait(group, DISPATCH_TIME_FOREVER);

在这个方法中的第二个参数指定等待时间,这里使用DISPATCH_TIME_FOREVER意味着永久等待,只要属于dispatch group中的处理尚未执行结束,就会一直等待,中途不能取消。
 
当然如同dispatch——after方法中那样,也可以指定等待时间为1秒等等。


//这里指定等待时间1s,即1s后查看dispatch group中的处理是否全部执行结束  
  

dispatch_time_t time = dispatch_time(DISPATCH_TIME_NOW, 1ull*NSEC_PER_SEC); 
 

  long result = dispatch_group_wait(group, time); 


   if (result == 0) { 
   

    //属于dispatch group中的全部处理都执行结束

 
    } 
 

  else { 
    

   //属于dispatch group的某一个处理还在执行  
  

}

//这里指定等待时间1s,即1s后查看dispatch group中的处理是否全部执行结束
  

dispatch_time_t time = dispatch_time(DISPATCH_TIME_NOW, 1ull*NSEC_PER_SEC);


   long result = dispatch_group_wait(group, time);
 

  if (result == 0) {
   

    //属于dispatch group中的全部处理都执行结束
    }
   

else {
    

   //属于dispatch group的某一个处理还在执行
    }


 
//这里也可以指定DISPATCH_TIME_NOW,则不用任何等待即可判断属于dispatch group中的处理是否全部执行结束  
 

long result = dispatch_group_wait(group, DISPATCH_TIME_NOW);

 //这里也可以指定DISPATCH_TIME_NOW,则不用任何等待即可判断属于dispatch group中的处理是否全部执行结束
 

  long result = dispatch_group_wait(group, DISPATCH_TIME_NOW);

 

 6、dispatch_barrier_async


dispatch_queue_t queue = dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_HIGH, 0); 
     


   dispatch_async(queue, ^{ 
 

      //表示执行数据读取任务  
 

      NSLog(@"blk1_reading"); 
   

}); 
   

dispatch_async(queue, ^{ 
    

   NSLog(@"blk2_reading"); 


   }); 
     
    dispatch_async(queue, ^{ 
     

  //表示执行数据写入处理任务  
     

  NSLog(@"blk1_writting"); 
  

}); 
     
    dispatch_async(queue, ^{ 
   

    NSLog(@"blk3_reading"); 
   

}); 
  

dispatch_async(queue, ^{ 
      

NSLog(@"blk4_reading");


    });

如果像上面那样简单的在dispatch_async方法中添加写入数据处理的任务,那么根据Concurrent Dispatch Queue并行执行的性质,就很有可能不是按照上面的添加处理任务的
顺序执行,那么在blk3_reading 和 blk4_reading执行读取数据的时候,blk1_writting进行写入数据的处理还没有执行到,那么后两次的读取数据操作读取到的数据就与期望中
的不符了。
解决这个问题的处理就是 使用 dispatch_barrier_async

 
dispatch_queue_t queue = dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_HIGH, 0); 
    


dispatch_async(queue, ^{ 
  

    //表示执行数据读取任务  


      NSLog(@"blk1_reading"); 
 

}); 
 

dispatch_async(queue, ^{ 
   

   NSLog(@"blk2_reading"); 


  }); 
    


  dispatch_barrier_async(queue, ^{ 
   

   //表示执行数据写入处理任务  
     

NSLog(@"blk1_writting"); 
   }); 
   


   dispatch_async(queue, ^{ 


      NSLog(@"blk3_reading"); 
   }); 
 

dispatch_async(queue, ^{ 
  

    NSLog(@"blk4_reading"); 


  }); 


使用dispatch_barrier_async方法,它会等待在它之前添加到 Concurrent Dispatch Queue的所有处理执行结束后,才执行该处理,然后等待该处理结束后,才接着处理后续添

加到Concurrent Dispatch Queue中的处理任务。当然在dispatch_barrier_async方法之前和之后添加的处理任务可以并发执行,即不保证执行顺序,但是可以确保
dispatch_barrier_async方法添加的任务一定是只能同时执行一个,按其添加任务顺序执行的,就是说,执行完blk1_reading和blk2_reading的读取数据任务后,才是进行

blk1_writting的写入数据任务,然后才是执行接着的读取数据的任务。



7、dispatch——sync
dispatch_async方法中的async意味着“非同步”,就是将指定的block非同步的添加到dispatch qeueue中,dispatch_async方法不做任何等待。
dispatch_sync方法中的sync意味着“同步”,也就是将指定的block同步追加到dispatch queue中,在追加block的过程结束之前,dispatch_sync方法会一直等待。
一旦调用dispatch_sync,那么在指定的处理执行结束之前,该方法不会返回,dispatch_sync方法可以简化代码,也可以说是简易版的dispatch_group_wait方法
  
dispatch_sync方法使用简单,但是容易引起死锁


dispatch_queue_t queue = dispatch_get_main_queue(); 
  

dispatch_sync(queue, ^{ 
     

  NSLog(@"引起死锁!"); 
 

  });

dispatch_queue_t queue = dispatch_get_main_queue();
  

dispatch_sync(queue, ^{
      

NSLog(@"引起死锁!");
 

  });


上面的代码在主线程中执行指定的block,并等待其执行结束,但是其实在主线程中就是在执行这些代码,所以就造成了死锁。

 

8、dispatch_apply

dispatch_apply 方法是 dispatch_sync 方法和Dispatch Group的关联API,该方法按指定的次数将指定的Block追加到指定的Dispatch Queue中,并等待全部处理执行结束

[cpp]
dispatch_queue_t queue = dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0); 
   

dispatch_apply(10, queue, ^(size_t index){ 
 

      NSLog(@"%zu",index); 
  

}); 


   NSLog(@"done");

因为是在Global Dispatch Queue中执行处理,所以各个处理的执行时间不定,也就是说输出1 2 3 ...的顺序不定。但是输出结果done必定是在最后的位置上的。因为dispatch_apply会等待所以的处理任务执行结束。
dispatch_apply 中的第一个参数是重复次数,第二个参数是追加对象的Dispatch Queue,第三个参数为追加的处理block,注意带参数


//假如对一个NSArray类对象的所有元素执行处理时,不必一个个编写for循环  
 

  NSArray *array = [[NSArray alloc] initWithObjects:@"string1",@"string2",@"string3", nil]; 
 

  dispatch_queue_t queue = dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0); 
  

dispatch_apply([array count], queue, ^(size_t index){ 
   

    NSLog(@"%zu : %@",index,[array objectAtIndex:index]); 
  

});


由于dispatch_apply方法也与dispatch_sync方法相同,会等待处理执行结束,因此推荐在dispatch_async函数中非同步的执行dispatch_apply方法。
例如:


NSArray *array = [[NSArray alloc] initWithObjects:@"string1",@"string2",@"string3", nil]; 


  dispatch_queue_t queue = dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0); 
 

//在Glocbal Dispatch Queue中非同步执行  
   dispatch_async(queue, ^{ 
        
   

   //等待dispatch_apply方法中的全部处理执行结束  
   

   dispatch_queue_t queue = dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0); 
   

   dispatch_apply([array count], queue, ^(size_t index){ 
       

   NSLog(@"%zu : %@",index,[array objectAtIndex:index]); 
    

  }); 
        
  

    //dispatch_apply方法中的全部处理任务执行结束  
     

  
       dispatch_async(dispatch_get_main_queue(), ^{ 
    

     //在主线程中执行处理  
           NSLog(@"done"); 
   

   }); 
    

  
   }); 

9、dispatch_suspend 和 dispatch_resume


//挂起指定的dispatch queue  
   

dispatch_suspend(<#dispatch_object_t object#>) 
 

  //恢复指定的dispatch queue  
  

dispatch_resume(<#dispatch_object_t object#>) 
 

  //这些方法对已经执行的处理没有影响,挂起后,追加到dispatch queue中但尚未处理的在此之后停止执行,而恢复后则使得这些处理能够继续执行。


10、dispatch_once


dispatch_once方法保证在应用程序执行中只执行一次指定处理的API。



static dispatch_once_t onceToken; 
   dispatch_once(&onceToken, ^{ 
 

    //code to be executed once

 
   });



你可能感兴趣的:(IOS,App)