簡體   English   中英

你如何編寫一個只能被調用一次的 Swift 完成塊?

[英]How do you write a Swift completion block that can only be called once?

假設我有一個存儲完成塊的 Swift 類,並執行一些異步任務。

我希望該塊由首先完成的任務調用,但只有那個 - 我不希望在第二個任務完成時再次調用它。

我怎樣才能以一種干凈的方式實現這一點?

只要你不需要它是線程安全的,你就可以用一個相當簡單的@propertyWrapper來解決這個問題。

@propertyWrapper
struct ReadableOnce<T> {
    var wrappedValue: T? {
        mutating get {
            defer { self._value = nil }
            return self._value
        }
        set {
            self._value = newValue
        }
    }
    private var _value: T? = nil
}

@ReadableOnce標記完成塊var ,它會在第一次讀取它的值后銷毀。

像這樣的東西:

class MyClass {
    @ReadableOnce private var completion: ((Error?) -> Void)?

    init(completion: @escaping ((Error?) -> Void)) {
        self.completion = completion
    }

    public func doSomething() {
        // These could all be invoked from different places, like your separate tasks' asynchronous callbacks
        self.completion?(error) // This triggers the callback, then the property wrapper sets it to nil.
        self.completion?(error) // This does nothing
        self.completion?(error) // This does nothing
    }
}

在這里寫了更詳細的討論,但要注意的關鍵是讀取值會將其設置為 nil,即使您不調用閉包! 對於不熟悉您編寫的智能屬性包裝器的人來說,這可能會令人驚訝。

已經有一個標准的一次性表達方式。 不幸的是,標准的 Objective-C 在 Swift 中不可用(GCD dispatch_once ),但標准的 Swift 技術可以正常工作,即具有惰性定義和調用初始化程序的屬性。

具體如何執行此操作取決於您希望強制執行一次性的級別。 在此示例中,它位於類實例級別:

class MyClass {
    // private part
    private let completion : (() -> ())
    private lazy var once : Void = {
        self.completion()
    }()
    private func doCompletionOnce() {
        _ = self.once
    }
    // public-facing part
    init(completion:@escaping () -> ()) {
        self.completion = completion
    }
    func doCompletion() {
        self.doCompletionOnce()
    }
}

在這里我們將測試它:

    let c = MyClass() {
        print("howdy")
    }
    c.doCompletion() // howdy
    c.doCompletion()
    let cc = MyClass() {
        print("howdy2")
    }
    cc.doCompletion() // howdy2
    cc.doCompletion()

如果將私有內容提升到類級別(使用靜態once屬性),則在整個程序的生命周期中只能執行一次完成。

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM