为链式函数使用 Swift 完成处理程序
Posted
技术标签:
【中文标题】为链式函数使用 Swift 完成处理程序【英文标题】:Working with Swift completion handlers for chained functions 【发布时间】:2018-07-02 18:44:34 【问题描述】:我将一些函数链接在一起,一旦所有函数都运行完毕,我不知道如何调用带有返回值的完成处理程序。
class AirQualityProvider
var aBlock: ((Int?) -> Void)?
func getAirQuality(completion: @escaping (Int?) -> Void)
aBlock = completion
callAPI()
private func callAPI()
let data = Data()
parseDataForAQI(data: data)
private func parseDataForAQI(data: Data)
for d in data
dosomeMath(d)
private func dosomeMath(data: Int)
// HERE IS WHERE I WANT IT TO SUM UP ALL THE NUMBERS
THEN ONLY RETURN ONE VALUE using a completion handler.
Currently, it returns the average as it is being generated.
在 Alexander 的帮助下几乎成功了。 Alexander 提供的代码完美运行,令人惊叹。问题是,当我在 alamofire 中运行 taskrunner 时,它返回空。在 alamofire 之外它照常工作。我需要在 alamofire 中运行它。
func A(json : JSON)
for (key,subJson) in json
if subJson["free"].doubleValue > 0.0
func B(asset: subJson["asset"].stringValue, json: subJson)
print(taskRunner.getResults())
func B(asset : String, json : JSON)
//OUTSIDE ALAMOFIRE WORKS
self.taskRunner.execute
return 100
Alamofire.request(url).responseJSON response in
//INSIDE ALAMOFIRE DOESN'T WORK. Returns []
self.taskRunner.execute
return 100
【问题讨论】:
这听起来像是DispatchGroup
的工作
感谢您的意见。 DispatchGroup 函数究竟是如何工作的?谢谢!
DispatchGroup
s 将等待所有异步调用完成,然后可能继续执行或调用通知函数。您能否从每个 doSomeMath 返回一些值,并将所有 mathResults 以某种方式组合成一个数字,然后在 parseDataForAQI(data:)
中调用 aBlock(numberPutInto)
之类的闭包?
@Red 你能把你的想法写成代码吗? ...考虑到函数“dosomemath”在循环中被调用,我看不出调度组如何解决这个问题。
@Alexander 请查看上面关于我使用 dispatchgroup 问题的评论
【参考方案1】:
我将使用调度队列来同步结果的聚合(通过同步Array.append(_:)
调用和随后的数组读取)。这是一个简单的例子:
import Dispatch
import Foundation
class ParallelTaskRunner<Result>
private var results = [Result]()
private let group = DispatchGroup()
private let resultAggregatorQueue = DispatchQueue(label: "Result Aggregator")
func execute(_ closure: (@escaping (Result) -> Void) -> Void)
group.enter() // Register that a new task is in-flight
closure result in
self.resultAggregatorQueue.sync // Synchronize access to the array
self.results.append(result) // Record the result
self.group.leave() // This task is done
func getResults() -> [Result]
group.wait() // Make sure all in-flight tasks are done
return resultAggregatorQueue.sync return results
let taskQueue = DispatchQueue(label: "Task Queue", attributes: .concurrent)
let taskRunner = ParallelTaskRunner<Int>()
for i in 0...100
taskRunner.execute completionHandler in
taskQueue.async // Simulated async computation
let randomTime = 3.0
print("Sleeping for \(randomTime)")
Thread.sleep(forTimeInterval: randomTime) // Simulates intesnive computation
let result = i // Simulate a result
completionHandler(result)
print(taskRunner.getResults()) // Oh look, all the results are here! :D
【讨论】:
感谢您的意见,看来这可行。考虑到我的课程非常长,我只是对如何将它应用到我的代码感到困惑。 @tenkdarko 为什么你的课很长很重要? (尽管这很好地表明您应该通过将其分解为更小、更简单的部分来简化它) 嗯,你能告诉我如何将此解决方案应用于我当前的问题吗?代码看起来不错,只是没有看到连接。 @tenkdarko 我不能特别具体,因为你的例子很模糊。但这里的重点是您可以遍历所有案例,使用我的ParallelTaskRunner
中的execute
方法对它们进行API 调用,然后您可以使用getResults()
收集所有结果,然后您可以将这些结果相加(或根据需要组合它们),并返回单个结果。
非常感谢您的帮助。你的代码太棒了。请查看我的编辑以查看我在使用您的代码时遇到的问题。您的代码可以完美运行,只是无法在 alamofire 中运行。它返回一个空数组。以上是关于为链式函数使用 Swift 完成处理程序的主要内容,如果未能解决你的问题,请参考以下文章
从 Java Script (TVML) 调用带有完成处理程序的 Swift 函数
使用完成处理程序(闭包)语法从objective-c文件调用swift文件中的函数
从 swift 评估 javascript 函数,在完成处理程序中得到 nil