【问题标题】:How do I re-use a block of code for a closure in Swift / Xcode 12.3如何在 Swift / Xcode 12.3 中重用代码块进行闭包
【发布时间】:2021-01-20 16:00:51
【问题描述】:

在我的 iOS 应用程序中,我正在运行一个 HKStatisticsCollectionQuery,它有一个

query.initialResultsHandler = { query, results, error in [...] }

还有一个

query.statisticsUpdateHandler = { query, hkStats, results, error in [...] }

两个闭包完全相同。

有没有办法只编写一次这些闭包的代码并引用它两次?通常我会重构/提取一个函数并调用它,但在这里我有一个

DispatchQueue.main.async { ... }

在处理程序内部,所以我不确定它是否会工作...正如您可能从我的问题中推断的那样,我不确定我是否正在关闭和 dispatchQueue 好吗...

【问题讨论】:

    标签: swift closures dispatch-queue


    【解决方案1】:

    闭包和函数是可以互换的。任何需要传递闭包的地方,都可以传递函数。

    因此,您可以为这两种情况编写一个函数并传递该函数名而不是闭包。

    也就是说,您的两个示例显示了不同的参数,这与您“两个闭包完全相同”的说法相矛盾。如果他们取不同的参数,怎么可能是一样的呢?

    编辑:

    考虑以下函数:

    func foo(value: String, completion: (String)->Void) {
        completion(value)
    }
    

    如您所料,我们可以使用闭包调用 foo:

    foo(value: "firstCall", completion: { value in
        print("in completion handler, value = '\(value)'")
    })
    

    那会输出

    在完成处理程序中,值 = 'firstCall'

    我们还可以定义一个或多个签名匹配完成处理程序的函数:

    func completionFunction(value: String) {
        print("In \(#function), value = '\(value)'")
    }
    
    func completionFunctionTwo(value: String) {
        print("In \(#function), value = '\(value)'")
    }
    

    然后这样调用:

    foo(value: "secondCall", completion: completionFunction)
    foo(value: "thirdCall", completion: completionFunctionTwo)
    

    请注意我们只是将函数名称作为完成处理程序传递。这相当于传递一个内联闭包。

    那些调用会输出:

    在completionFunction(value:)中,value = 'secondCall'

    在 completionFunctionTwo(value:), value = 'thirdCall'

    最后,您可以创建一个包含闭包的变量,并将其作为您的完成处理程序传递:

    let aCompletionClosure: (String) -> Void = { value in
        print("In completion closure, value = '\(value)'")
    }
    
    foo(value: "forthCall", completion: aCompletionClosure)
    

    输出:

    在完成闭包中,value = 'forthCall'

    【讨论】:

    • 我没有在更新处理程序中使用“额外”的 hkStats。它就在那里,因为在苹果的文档中,它是传递给闭包的第二个属性。我仍然不知道我是否可以忽略它,但这是一个不同的话题......也许稍后。 - - 反正。非常感谢您的长回答。我得消化一下,可能需要一段时间......
    【解决方案2】:

    由于你的闭包有不同的参数,你需要创建一个函数,它可以在两个闭包中调用:

    func handle(query: ...?, results: ...?, error: Error?) {
        //...
    }
    

    由于第一个处理程序的参数与您的函数完全相同,您可以简单地将其分配给处理程序:

    query.initialResultsHandler = handle
    

    或者你可以从你的闭包中调用它:

    query.initialResultsHandler = { query, results, error in 
        self.handle(query: query, results: results, error: error)
    }
    

    在第二个处理程序中,参数不同,所以你可以调用它:

    query.statisticsUpdateHandler = { query, hkStats, results, error in 
        self.handle(query: query, results: results, error: error)
    }
    

    或者,您可以定义第二个函数,它匹配第二个闭包签名,并从中调用第一个函数:

    func handleUpdate(query: ...?, hkStats: ...?, results: ...?, error: Error?) {
        handle(query: query, results; results, error: error)
    }
    

    在这种情况下,您还可以将该函数分配给第二个处理程序:

    query.statisticsUpdateHandler = handleUpdate
    

    【讨论】:

      猜你喜欢
      • 2015-10-08
      • 1970-01-01
      • 1970-01-01
      • 2021-04-13
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2016-02-29
      • 1970-01-01
      相关资源
      最近更新 更多