首页 > 代码库 > 完整详解GCD系列(二)dispatch_after;dispatch_apply;dispatch_once

完整详解GCD系列(二)dispatch_after;dispatch_apply;dispatch_once

一、dispatch_after
功能:延迟一段时间把一项任务提交到队列中执行,返回之后就不能取消
常用来在在主队列上延迟执行一项任务
函数原型

[plain] view plaincopy
  1. func dispatch_after(_ when: dispatch_time_t,  
  2.                   _ queue: dispatch_queue_t!,  
  3.                   _ block: dispatch_block_t!)  

参数

[plain] view plaincopy
  1.        when 过了多久执行的时间间隔  
  2. queue   提交到的队列  
  3. block   执行的任务  



例如:可以利用dispatch_after写一个自己用的Delay函数,delay一段时间在主线程上执行一段代码

[plain] view plaincopy
  1. func hwcDelay(delay:Double, closure:()->()) {  
  2.     dispatch_after(  
  3.         dispatch_time(  
  4.             DISPATCH_TIME_NOW,  
  5.             Int64(delay * Double(NSEC_PER_SEC))  
  6.         ),  
  7.         dispatch_get_main_queue(), closure)  
  8. }  


只需要这样使用
hwcDelay(0.5){
//Do everything you want
}
比如,当用户的应用不满足某些我们App需要的条件时候(例如,我们的App需要蓝牙打开),然后在APP启动的时候测到蓝牙Off后,应当给用户一个提示。在view载入完成后,延迟给用户一个提示,也可以给这个提示添加一些动画,要比view在载入完成直接显示提示要有好的多。
举例
在viewLoad后,延迟1s,提示一个alertview

[plain] view plaincopy
  1. class ViewController: UIViewController{      
  2.     func hwcDelay(delay:Double, closure:()->()) {  
  3.     dispatch_after(  
  4.         dispatch_time(  
  5.             DISPATCH_TIME_NOW,  
  6.             Int64(delay * Double(NSEC_PER_SEC))  
  7.         ),  
  8.         dispatch_get_main_queue(), closure)  
  9. }    
  10.     override func viewDidLoad(){      
  11.         super.viewDidLoad()      
  12.         hwcDelay(1.0){  
  13.         var alertview = UIAlertView(title:"Dispatch_after",message:"Message",delegate:self,cancelButtonTitle:"OK")  
  14.         alertview.show()  
  15.     }            
  16.     }      
  17.     override func didReceiveMemoryWarning(){      
  18.         super.didReceiveMemoryWarning()      
  19.     }      
  20. }   


二、dispatch_apply
功能:把一项任务提交到队列中多次执行,具体是并行执行还是串行执行由队列本身决定.注意,dispatch_apply不会立刻返回,在执行完毕后才会返回,是同步的调用。

[plain] view plaincopy
  1. func dispatch_apply(_ iterations: UInt,  
  2.                   _ queue: dispatch_queue_t!,  
  3.                   _ block: ((UInt) -> Void)!)  

参数

[plain] view plaincopy
  1. iterations  执行的次数  
  2.     queue       提交到的队列  
  3.     block       执行的任务  


那么,何时使用这个函数呢?从它的功能不难看出,如果我们可以把不相关的循环提交到后台线程并行执行,并且循环任务调度到后台执行的效率提高,能抵消掉队列调度本身的开销,那么效率会显著提高。

举例
比如我有一个数组,存储了一系列对象,初始化的时候,这些对象都要调用一次某函数来进行相关的计算。这些计算相互没有影响。这时,我们就可以用dispatch_apply来使用异步队列来初始化.这里把这种情况进行简化

[plain] view plaincopy
  1. class ViewController: UIViewController{      
  2.     var hwcarray = ["hello","hwc","hellohwc"]  
  3.     override func viewDidLoad(){      
  4.         super.viewDidLoad()      
  5.         dispatch_apply(3,dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT,0)){  
  6.         (index:UInt) -> () in  
  7.         var expObject = self.hwcarray[Int(index)] as NSString  
  8.         NSLog("%d",expObject.length)  
  9.     }    
  10.     NSLog("Dispatch_after is over")       
  11.     }      
  12.     override func didReceiveMemoryWarning(){      
  13.         super.didReceiveMemoryWarning()      
  14.     }      
  15. }   

可以看到,输出是

[plain] view plaincopy
  1. 3  
  2. 5  
  3. 8  
  4. dispatch_after is over  

由于这样会阻塞主线程,而下文又与dispatch_apply的执行结果无关,所以可以在异步队列中掉dispatch_apply,然后执行完成后进行通知

[plain] view plaincopy
  1. class ViewController: UIViewController{      
  2.     var hwcarray = ["hello","hwc","hellohwc"]  
  3.     override func viewDidLoad(){   
  4.         super.viewDidLoad()  
  5.     dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT,0)){  
  6.      dispatch_apply(3,dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT,0)){  
  7.         (index:UInt) -> () in  
  8.         var expObject = self.hwcarray[Int(index)] as NSString  
  9.         NSLog("%d",expObject.length)  
  10.      }  
  11.      NSLog("Dispatch_after in global queue is over")    
  12.     }      
  13.          
  14.     NSLog("Dispatch_after in main queue is over")       
  15.     }      
  16.     override func didReceiveMemoryWarning(){      
  17.         super.didReceiveMemoryWarning()      
  18.     }      
  19. }  

这样输出为

[plain] view plaincopy
  1. 8  
  2. Dispatch_after in main queue is over  
  3. 3  
  4. 5  
  5. Dispatch_after in global queue is over  

可以看到,相对主队列(主线程)是异步的,在global队列中是并行执行的
三、dispatch_once
功能:保证在APP运行期间,block中的代码只执行一次
func dispatch_once(_ predicate: UnsafeMutablePointer<dispatch_once_t>,
                 _ block: dispatch_block_t!)
参数
predicate 用来判断提交的block是否执行完成
block 执行一次的任务
dispatch_once的经典实用场景是单例
单例代码:

[plain] view plaincopy
  1. class hwcSingleton {  
  2.      var testVariable:Int!  
  3.      func print(){  
  4.     testVariable = testVariable + 1  
  5.     println(testVariable)  
  6.     }  
  7.     class var sharedObject: hwcSingleton {  
  8.         struct StaticStruct {  
  9.             static var predicate : dispatch_once_t = 0  
  10.             static var instance : hwcSingleton? = nil  
  11.         }  
  12.         dispatch_once(&StaticStruct.predicate) {  
  13.             StaticStruct.instance = hwcSingleton()  
  14.        StaticStruct.instance?.testVariable = 10  
  15.         }  
  16.         return StaticStruct.instance!  
  17.     }  

完整详解GCD系列(二)dispatch_after;dispatch_apply;dispatch_once