ios - after - swift delay block




dispatch_after-GCD在swift中? (13)

我已經瀏覽了Apple的iBook ,並且找不到它的任何定義:

有人可以解釋dispatch_after的結構嗎?

dispatch_after(<#when: dispatch_time_t#>, <#queue: dispatch_queue_t?#>, <#block: dispatch_block_t?#>)

1)添加此方法作為UIViewController擴展的一部分。

extension UIViewController{
func runAfterDelay(delay: NSTimeInterval, block: dispatch_block_t) {
        let time = dispatch_time(DISPATCH_TIME_NOW, Int64(delay * Double(NSEC_PER_SEC)))
        dispatch_after(time, dispatch_get_main_queue(), block)
    }
}

在VC上調用此方法:

    self.runAfterDelay(5.0, block: {
     //Add code to this block
        print("run After Delay Success")
    })

2)performSelector(“yourMethod Name”,withObject:nil,afterDelay:1)

3)

override func viewWillAppear(animated: Bool) {

dispatch_after(dispatch_time(DISPATCH_TIME_NOW, 2), dispatch_get_main_queue(), { () -> () in
    //Code Here
})

//緊湊形式

dispatch_after(dispatch_time(DISPATCH_TIME_NOW, 2), dispatch_get_main_queue()) {
    //Code here
}

}


Apple為Objective-C提供了一個dispatch_after片段

dispatch_after(dispatch_time(DISPATCH_TIME_NOW, (int64_t)(<#delayInSeconds#> * NSEC_PER_SEC)), dispatch_get_main_queue(), ^{
    <#code to be executed after a specified delay#>
});

這裡是與Swift 3相同的代碼片段:

DispatchQueue.main.asyncAfter(deadline: DispatchTime.now() + <#delayInSeconds#>) {
  <#code to be executed after a specified delay#>
}

馬特的語法非常好,如果你需要使塊無效,你可能想使用這個:

typealias dispatch_cancelable_closure = (cancel : Bool) -> Void

func delay(time:NSTimeInterval, closure:()->Void) ->  dispatch_cancelable_closure? {

    func dispatch_later(clsr:()->Void) {
        dispatch_after(
            dispatch_time(
                DISPATCH_TIME_NOW,
                Int64(time * Double(NSEC_PER_SEC))
            ),
            dispatch_get_main_queue(), clsr)
    }

    var closure:dispatch_block_t? = closure
    var cancelableClosure:dispatch_cancelable_closure?

    let delayedClosure:dispatch_cancelable_closure = { cancel in
        if closure != nil {
            if (cancel == false) {
                dispatch_async(dispatch_get_main_queue(), closure!);
            }
        }
        closure = nil
        cancelableClosure = nil
    }

    cancelableClosure = delayedClosure

    dispatch_later {
        if let delayedClosure = cancelableClosure {
            delayedClosure(cancel: false)
        }
    }

    return cancelableClosure;
}

func cancel_delay(closure:dispatch_cancelable_closure?) {

    if closure != nil {
        closure!(cancel: true)
    }
}

使用如下

let retVal = delay(2.0) {
    println("Later")
}
delay(1.0) {
    cancel_delay(retVal)
}

credits

上面的鏈接似乎是關閉的。 來自Github的原始Objc代碼


Swift 3.0和Swift 4.0中最簡單的解決方案

func delayWithSeconds(_ seconds: Double, completion: @escaping () -> ()) {
    DispatchQueue.main.asyncAfter(deadline: .now() + seconds) { 
        completion()
    }
}

用法

delayWithSeconds(1) {
   //Do something
}

Swift 3&4:

您可以在DispatchQueue上創建擴展並添加在內部使用DispatchQueue asyncAfter函數的函數延遲

extension DispatchQueue {
    static func delay(_ delay: DispatchTimeInterval, closure: @escaping () -> ()) {
        let timeInterval = DispatchTime.now() + delay
        DispatchQueue.main.asyncAfter(deadline: timeInterval, execute: closure)
    }
}

使用:

DispatchQueue.delay(.seconds(1)) {
    print("This is after delay")
}

在Swift 3.0中

調度隊列

  DispatchQueue(label: "test").async {
        //long running Background Task
        for obj in 0...1000 {
            print("async \(obj)")
        }

        // UI update in main queue
        DispatchQueue.main.async(execute: { 
            print("UI update on main queue")
        })

    }

    DispatchQueue(label: "m").sync {
        //long running Background Task
        for obj in 0...1000 {
            print("sync \(obj)")
        }

        // UI update in main queue
        DispatchQueue.main.sync(execute: {
            print("UI update on main queue")
        })
    }

5秒後發貨

    DispatchQueue.main.after(when: DispatchTime.now() + 5) {
        print("Dispatch after 5 sec")
    }

我總是喜歡使用擴展而不是免費功能。

斯威夫特4

public extension DispatchQueue {

  private class func delay(delay: TimeInterval, closure: @escaping () -> Void) {
    let when = DispatchTime.now() + delay
    DispatchQueue.main.asyncAfter(deadline: when, execute: closure)
  }

  class func performAction(after seconds: TimeInterval, callBack: @escaping (() -> Void) ) {
    DispatchQueue.delay(delay: seconds) {
      callBack()
    }
  }

}

使用如下。

DispatchQueue.performAction(after: 0.3) {
  // Code Here
}

使用此代碼在2.0秒後執行一些與UI相關的任務。

            let delay = 2.0
            let delayInNanoSeconds = dispatch_time(DISPATCH_TIME_NOW, Int64(delay * Double(NSEC_PER_SEC)))
            let mainQueue = dispatch_get_main_queue()

            dispatch_after(delayInNanoSeconds, mainQueue, {

                print("Some UI related task after delay")
            })

Swift 3.0版本

在關閉功能後,在主線程上延遲執行一些任務。

func performAfterDelay(delay : Double, onCompletion: @escaping() -> Void){

    DispatchQueue.main.asyncAfter(deadline: DispatchTime.now() + delay, execute: {
       onCompletion()
    })
}

像這樣調用這個函數:

performAfterDelay(delay: 4.0) {
  print("test")
}

另一種方法是像這樣擴展Double:

extension Double {
   var dispatchTime: dispatch_time_t {
       get {
           return dispatch_time(DISPATCH_TIME_NOW,Int64(self * Double(NSEC_PER_SEC)))
       }
   }
}

那麼你可以像這樣使用它:

dispatch_after(Double(2.0).dispatchTime, dispatch_get_main_queue(), { () -> Void in
            self.dismissViewControllerAnimated(true, completion: nil)
    })

我喜歡馬特的延遲功能,但只是出於偏好,我寧願限制傳球關閉。


對結構更清晰的概念:

dispatch_after(when: dispatch_time_t, queue: dispatch_queue_t, block: dispatch_block_t?)

dispatch_time_t是一個UInt64dispatch_queue_t實際上是一個類型別名的NSObject ,但你應該使用你熟悉的GCD方法來獲得隊列。 該塊是一個Swift閉包。 具體來說, dispatch_block_t被定義為() -> Void ,相當於() -> ()

用法示例:

let delayTime = dispatch_time(DISPATCH_TIME_NOW, Int64(1 * Double(NSEC_PER_SEC)))
dispatch_after(delayTime, dispatch_get_main_queue()) {
    print("test")
}

編輯:

我推薦使用@ matt的非常好的delay功能

編輯2:

在Swift 3中,GCD將會有新的包裝。 看到這裡: https://github.com/apple/swift-evolution/blob/master/proposals/0088-libdispatch-for-swift3.md : https://github.com/apple/swift-evolution/blob/master/proposals/0088-libdispatch-for-swift3.md

在Swift 3中,原始示例將被編寫如下:

let deadlineTime = DispatchTime.now() + .seconds(1)
DispatchQueue.main.asyncAfter(deadline: deadlineTime) {
    print("test")
}

請注意,您可以將deadlineTime聲明寫為DispatchTime.now() + 1.0並獲得相同的結果,因為+運算符如下覆蓋(類似於- ):

  • func +(time: DispatchTime, seconds: Double) -> DispatchTime
  • func +(time: DispatchWalltime, interval: DispatchTimeInterval) -> DispatchWalltime

這意味著如果您不使用DispatchTimeInterval enum並只寫一個數字,則假定您使用的是秒。


為了擴大Cezary的答案,在1納秒後執行,我必須在4秒半後執行以下操作。

    let delay = 4.5 * Double(NSEC_PER_SEC)
    let time = dispatch_time(DISPATCH_TIME_NOW, Int64(delay))
    dispatch_after(time, dispatch_get_main_queue(), block)

編輯:我發現我的原始代碼有點不對。 如果不將NSEC_PER_SEC轉換為Double,則隱式鍵入會導致編譯錯誤。

如果任何人都可以提出更優化的解決方案,我很樂意聽到它。

==更新Swift 3 ==

這在Swift 3中非常容易和優雅:

    DispatchQueue.main.asyncAfter(deadline: .now() + 4.5) {
        // ...
    }

現在,Swift中的Grand Central Dispatch(GCD)中的異步調度不僅僅是語法糖。

添加Podfile

pod 'AsyncSwift'

然後,你可以像這樣使用它。

let seconds = 3.0
Async.main(after: seconds) {
print("Is called after 3 seconds")
}.background(after: 6.0) {
print("At least 3.0 seconds after previous block, and 6.0 after Async code is called")
}

雖然不是OP的原始問題,但是某些與NSTimer相關的問題已被標記為該問題的重複,因此在這裡值得包含NSTimer答案。

NSTimer vs dispatch_after

  • NSTimer更高, dispatch_after更低。
  • NSTimer更容易取消。 取消dispatch_after需要編寫更多代碼 。

使用NSTimer延遲任務

創建一個NSTimer實例。

var timer = NSTimer()

以您需要的延遲啟動計時器。

// invalidate the timer if there is any chance that it could have been called before
timer.invalidate()
// delay of 2 seconds
timer = NSTimer.scheduledTimerWithTimeInterval(2.0, target: self, selector: #selector(delayedAction), userInfo: nil, repeats: false) 

添加一個要在延遲之後調用的函數(使用上面selector參數使用的任何名稱)。

func delayedAction() {
    print("Delayed action has now started."
}

筆記

  • 如果您需要在發生之前取消操作,只需調用timer.invalidate()
  • 對於重複動作, repeats: true使用repeats: true
  • 如果您有一次性事件而無需取消,則不需要創建timer實例變量。 以下就足夠了:

    NSTimer.scheduledTimerWithTimeInterval(2.0, target: self, selector: #selector(delayedAction), userInfo: nil, repeats: false) 
    
  • here看到我更完整的答案。





grand-central-dispatch