Swift4中如何返回受线程影响的数值?附相关代码示例
在Swift 4中正确返回受异步线程影响的数值
这是个非常典型的异步任务结果传递问题,咱们先拆解一下你代码里的核心问题,再给出靠谱的解决方案。
你的代码里的核心问题
food?.getFoods()是一个异步操作——它会在后台线程执行网络请求或者耗时任务,等任务完成后才会调用闭包里的代码。如果试图直接在函数外部拿sortedFood或者foodWithEname的值,大概率会拿到空值,因为异步任务还没跑完呢。而且你代码里的可选值处理(比如强制解包left.hits!)也有崩溃风险。
正确的实现方式
我们需要利用好函数参数里的completion闭包,在异步任务完成、数据处理完毕后,把结果通过回调传递出去,同时注意线程安全(比如UI操作必须在主线程)。
func getAll(completion: (([Foods]?, Error?) -> Void)?){ let food = Food() // 不需要声明为可选,直接初始化即可 food.getFoods { [weak self] (foodsArray, error) in // 先确保completion闭包存在,不然白忙活 guard let completion = completion else { return } // 优先处理错误情况 if let error = error { completion(nil, error) return } // 校验原始数据是否存在 guard let originalFoods = foodsArray else { let emptyError = NSError(domain: "FoodService", code: -1, userInfo: [NSLocalizedDescriptionKey: "未获取到食物数据"]) completion(nil, emptyError) return } // 优雅处理排序逻辑,避免强制解包 let sortedFoods = originalFoods.sorted { left, right in switch (left.hits, right.hits) { case (.some(let leftHits), .some(let rightHits)): return leftHits > rightHits case (.some, .none): // 左边有点击量,右边没有,左边排前面 return true case (.none, .some): // 右边有点击量,左边没有,右边排前面 return false case (.none, .none): // 都没有点击量,保持原顺序或者返回false return false } } // 处理ename赋值逻辑(这里补全你的业务代码) var processedFoods: [Foods] = [] for foodItem in sortedFoods { // 假设你这里有获取ename的逻辑,比如从本地缓存或者其他接口拿到 let ename = "对应的英文名称" // 替换成你的实际逻辑 let processedItem = Foods(fid: foodItem.fid, fname: foodItem.fname, hits: foodItem.hits, addr: foodItem.addr, ename: ename) processedFoods.append(processedItem) } // 如果调用方需要更新UI,必须切回主线程执行回调 DispatchQueue.main.async { completion(processedFoods, nil) } } }
关键要点解释
- 弱引用
self:如果你的闭包里需要访问当前类的属性/方法,加上[weak self]可以避免循环引用,防止内存泄漏。 - 错误优先处理:先检查错误,再处理有效数据,逻辑更清晰,也能提前终止无效流程。
- 安全的可选值处理:用
switch替代嵌套if let,排序逻辑更易读,彻底避免强制解包!带来的崩溃风险。 - 主线程回调:绝大多数情况下,调用
getAll的地方是要更新UI的,而UI操作必须在主线程执行,所以用DispatchQueue.main.async把回调切回主线程。 - 通过completion传递结果:异步任务完成后才调用completion,确保调用方拿到的是处理完毕的有效数据,而不是空值。
调用示例
// 调用getAll函数,处理返回结果 getAll { foods, error in if let error = error { print("获取食物数据失败:\(error.localizedDescription)") return } guard let foods = foods else { print("没有可用的食物数据") return } // 这里可以处理拿到的排序后食物数组,比如更新TableView print("成功获取到\(foods.count)条食物数据") }
内容的提问来源于stack exchange,提问作者Soonmyun Jang
相关产品推荐
相关产品推荐

