GCD延遲執行如何在中途取消

SSBun發表於2017-12-13

GCD 是我們常用的多執行緒技術,基於C語言給我們帶來了高效的執行速度,通過block讓程式碼的呼叫更加緊湊。但是對GCD中任務的管理確實十分麻煩的事情,一般情況下如果要管理多執行緒的任務,我們會轉而使用 NSOpeartion。 如果問題複雜的話,我當然還是推薦使用 NSOpeartion, 但是如果我們只是為了延遲程式碼的執行,我們肯定更願意使用 DispathAfter這樣簡單的方法,這裡如果你想要在某種情況下取消未執行的操作,我們該怎麼辦呢.

我在閱讀王魏的 《Swfit Tips》時看到了他所實現的一個寫法,感覺很棒,這裡稍加修改讓它更好用一點。

import Foundation



typealias Task = (_ cancel: Bool) -> ()

@discardableResult func delay(_ time: TimeInterval, task: @escaping () -> ()) -> Task?{
    
    func dispatch_later(block: @escaping () -> ()) {
        let t = DispatchTime.now() + time
        DispatchQueue.main.asyncAfter(deadline: t, execute: block)
    }
    
    
    var closure: (() -> Void)? = task
    var result: Task?
    
    let delayedClosure: Task = {
        cancel in
        if let closure = closure {
            if !cancel {
                DispatchQueue.main.async(execute: closure)
            }
        }
        closure = nil
        result = nil
    }
    
    result = delayedClosure
    
    dispatch_later {
        if let result = result {
            result(false)
        }
    }

    return result
}

func cancel(_ task: Task?) {
    task?(true)
}

複製程式碼

使用起來也是很簡單,如下

let a = delay(4) {
    print("hello one !")
}
let b = delay(6) {
    print("hello two !")
}

delay(5) {
    cancel(a)
    cancel(b)
}
複製程式碼

這裡, 我們在5秒後,同時取消了a和b,但是a在4秒後就已經執行了,而b將會在執行前被取消。所以你只能看到列印結果 "hello one !"

End

相關文章