【问题标题】:Swift completion in defer延迟中的快速完成
【发布时间】:2020-05-15 12:10:47
【问题描述】:

我喜欢defer,因为在复杂的多case场景下,我不能忘记在函数结束前调用completion。

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

这是我通常做的:

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


    【解决方案1】:

    我认为您不应该将代码放入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!") // or whatever error handling or logging you want to do in that case
        }
    
        // 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!
    }
    

    【讨论】:

    • 如果延迟在完成之前运行会发生什么?想象一下 doSomethingElse 是一个异步任务,那么断言就会失败,我不想这样。
    • 是的,当然。我想如果有更多的异步性,而不是只在执行时发出收据,你可以例如还发出一个已经将闭包“移交”给代表的问题(理想情况下,它有自己的机制来保证传输或执行)。
    猜你喜欢
    • 2020-02-29
    • 2011-06-18
    • 1970-01-01
    • 2014-07-26
    • 1970-01-01
    • 1970-01-01
    • 2016-10-07
    • 1970-01-01
    • 2023-04-03
    相关资源
    最近更新 更多