1. 程式人生 > >完整詳解GCD系列(二)dispatch_after;dispatch_apply;dispatch_

完整詳解GCD系列(二)dispatch_after;dispatch_apply;dispatch_

本教涵蓋的內容
一、dispatch_after
二、dispatch_apply 
三、dispatch_once

一、dispatch_after
功能:延遲一段時間把一項任務提交到佇列中執行,返回之後就不能取消
常用來在在主佇列上延遲執行一項任務
函式原型
func dispatch_after(_ when: dispatch_time_t,
                  _ queue: dispatch_queue_t!,
                  _ block: dispatch_block_t!)
引數
        when	過了多久執行的時間間隔
	queue	提交到的佇列
	block	執行的任務


例如:可以利用dispatch_after寫一個自己用的Delay函式,delay一段時間在主執行緒上執行一段程式碼
func hwcDelay(delay:Double, closure:()->()) {
    dispatch_after(
        dispatch_time(
            DISPATCH_TIME_NOW,
            Int64(delay * Double(NSEC_PER_SEC))
        ),
        dispatch_get_main_queue(), closure)
}

只需要這樣使用
hwcDelay(0.5){
//Do everything you want
}
比如,當用戶的應用不滿足某些我們App需要的條件時候(例如,我們的App需要藍芽開啟),然後在APP啟動的時候測到藍芽Off後,應當給使用者一個提示。在view載入完成後,延遲給使用者一個提示,也可以給這個提示新增一些動畫,要比view在載入完成直接顯示提示要有好的多。
舉例
在viewLoad後,延遲1s,提示一個alertview
class ViewController: UIViewController{    
    func hwcDelay(delay:Double, closure:()->()) {
    dispatch_after(
        dispatch_time(
            DISPATCH_TIME_NOW,
            Int64(delay * Double(NSEC_PER_SEC))
        ),
        dispatch_get_main_queue(), closure)
}  
    override func viewDidLoad(){    
        super.viewDidLoad()    
        hwcDelay(1.0){
		var alertview = UIAlertView(title:"Dispatch_after",message:"Message",delegate:self,cancelButtonTitle:"OK")
		alertview.show()
	}          
    }    
    override func didReceiveMemoryWarning(){    
        super.didReceiveMemoryWarning()    
    }    
} 

二、dispatch_apply
功能:把一項任務提交到佇列中多次執行,具體是並行執行還是序列執行由佇列本身決定.注意,dispatch_apply不會立刻返回,在執行完畢後才會返回,是同步的呼叫。
func dispatch_apply(_ iterations: UInt,
                  _ queue: dispatch_queue_t!,
                  _ block: ((UInt) -> Void)!)
引數
iterations	執行的次數
	queue		提交到的佇列
	block		執行的任務

那麼,何時使用這個函式呢?從它的功能不難看出,如果我們可以把不相關的迴圈提交到後臺執行緒並行執行,並且迴圈任務排程到後臺執行的效率提高,能抵消掉佇列排程本身的開銷,那麼效率會顯著提高。

舉例
比如我有一個數組,儲存了一系列物件,初始化的時候,這些物件都要呼叫一次某函式來進行相關的計算。這些計算相互沒有影響。這時,我們就可以用dispatch_apply來使用非同步佇列來初始化.這裡把這種情況進行簡化
class ViewController: UIViewController{    
    var hwcarray = ["hello","hwc","hellohwc"]
    override func viewDidLoad(){    
        super.viewDidLoad()    
        dispatch_apply(3,dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT,0)){
		(index:UInt) -> () in
		var expObject = self.hwcarray[Int(index)] as NSString
		NSLog("%d",expObject.length)
	}  
	NSLog("Dispatch_after is over")     
    }    
    override func didReceiveMemoryWarning(){    
        super.didReceiveMemoryWarning()    
    }    
} 
可以看到,輸出是
3
5
8
dispatch_after is over
由於這樣會阻塞主執行緒,而下文又與dispatch_apply的執行結果無關,所以可以在非同步佇列中掉dispatch_apply,然後執行完成後進行通知
class ViewController: UIViewController{    
    var hwcarray = ["hello","hwc","hellohwc"]
    override func viewDidLoad(){ 
        super.viewDidLoad()
	dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT,0)){
	 dispatch_apply(3,dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT,0)){
		(index:UInt) -> () in
		var expObject = self.hwcarray[Int(index)] as NSString
		NSLog("%d",expObject.length)
	 }
	 NSLog("Dispatch_after in global queue is over")  
	}    
       
	NSLog("Dispatch_after in main queue is over")     
    }    
    override func didReceiveMemoryWarning(){    
        super.didReceiveMemoryWarning()    
    }    
}
這樣輸出為
8
Dispatch_after in main queue is over
3
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的經典實用場景是單例
單例程式碼:
class hwcSingleton {
     var testVariable:Int!
     func print(){
	testVariable = testVariable + 1
	println(testVariable)
	}
    class var sharedObject: hwcSingleton {
        struct StaticStruct {
            static var predicate : dispatch_once_t = 0
            static var instance : hwcSingleton? = nil
        }
        dispatch_once(&StaticStruct.predicate) {
            StaticStruct.instance = hwcSingleton()
	   StaticStruct.instance?.testVariable = 10
        }
        return StaticStruct.instance!
    }
}

當然也可以在多執行緒環境下,保證一段程式碼只執行一次。