快速完成延迟

问题描述 投票:1回答:2

我喜欢延迟,因为在具有多案例情况的复杂函数中,我不能忘记在函数结束之前调用完成。

但是当完成传递给另一个函数时,不应在第一个函数的延迟中运行它。

这是我通常要做的:

func doSomething(completion: ()->()) {
    /// Set this to false, before passing the completion to another function.
    var runCompletionInDefer = true
    defer {
        if runCompletionInDefer { completion() }
    }
    runCompletionInDefer = false
    doSomethingElse { completion() }
}

func doSomethingElse(completion: ()->()) {
    completion()
}

有更好的解决方案吗?

使用这种方法,在将完成传递给另一个函数之前,您仍然必须记住要这样做:

runCompletionInDefer = false
swift deferred completionhandler
2个回答
0
投票

是否有理由无法将您的defer块中的代码移入完成处理程序?

Defer很好,但是我们肯定需要使用defer来解决。


0
投票

[我不认为您应该将代码放入defer中,直到您确信每次到达函数末尾都确实要执行该代码。

所以让我建议,也许您实际想要的defer并不是完成闭包的字面执行,而是一种检查,它使您有信心当时那个人已经在某个地方调用了闭包达到defer。一种“执行收据”。

为此,可以将闭包包装到跟踪其执行的结构中。这是一个这样的包装看起来像的例子:

protocol CompletionReceiptProtocol {
    associatedtype Closure: Any
    var receipt: Bool { get }
    func execute()
}

class SomethingCompletion: CompletionReceiptProtocol {
    typealias Closure = (()->Void)

    var receipt = false
    private var closure: Closure

    init(_ closure: @escaping Closure) {
        self.closure = closure
    }

    func execute() {
        self.closure()
        self.receipt = true
    }

}

这是使用包装器的方式:

func doSomething(completion nakedCompletion: @escaping ()->Void) {
    let completion = SomethingCompletion(nakedCompletion)
    defer {
        assert(completion.receipt , "Oops! End of function reached without completion being called!")
    }

    // Scenario A: `doSomething` executes the completion itself
    completion.execute()

    // Scenario B: `doSomething` delegates the completion to `doSomethingElse`...
    doSomethingElse(completion: completion)
}

func doSomethingElse(completion: SomethingCompletion) {
    completion.execute() //... and it's called here instead. So it's all good!
}
© www.soinside.com 2019 - 2024. All rights reserved.