Swift 4中如何在if let语句及异步任务内返回函数值?
解决异步任务返回值与Core Data存储的问题
首先得明确你当前代码的核心问题:loadUrl里的异步任务(DispatchQueue.global().async)是在后台线程执行的,函数本身会立刻执行完毕并返回——这时候异步任务还没拿到数据呢,所以根本没法直接从函数返回异步获取到的cityStateLocation。
咱们可以通过闭包回调的方式解决这个问题,让异步任务完成后通知调用方拿到结果,再处理Core Data的存储。下面是具体的修改步骤:
1. 重构loadUrl函数,改用闭包回调返回结果
把原来的返回值类型改成接受一个完成回调闭包,这样异步任务完成后就能把结果传递出去:
func loadUrl(url: String, completion: @escaping (String?, Error?) -> Void) { DispatchQueue.global().async { do { // 替换强制解包,避免崩溃 guard let appUrl = URL(string: url) else { throw NSError(domain: "InvalidURL", code: 0, userInfo: [NSLocalizedDescriptionKey: "URL格式错误"]) } let data = try Data(contentsOf: appUrl) guard let json = try JSONSerialization.jsonObject(with: data) as? [String: Any] else { throw NSError(domain: "InvalidJSON", code: 1, userInfo: [NSLocalizedDescriptionKey: "JSON解析失败"]) } print("Test from do") // 用链式可选绑定简化多层判断 if let results = json["results"] as? [[String: Any]], let firstResult = results.first, let cityStateLocation = firstResult["formatted_address"] as? String { print("Test from if let chain") // 切回主线程传递结果(Core Data操作建议在主线程或指定上下文线程执行) DispatchQueue.main.async { completion(cityStateLocation, nil) } return } // 处理未获取到地址的情况 DispatchQueue.main.async { completion(nil, NSError(domain: "NoLocationData", code: 2, userInfo: [NSLocalizedDescriptionKey: "未获取到地址信息"])) } } catch { DispatchQueue.main.async { completion(nil, error) print("Cannot connect to the server: \(error.localizedDescription)") } } } }
这里做了几个关键优化:
- 用
guard let替代强制解包,避免因数据格式异常导致崩溃 - 把结果通过
completion闭包传递,并且切换回主线程保证后续操作的线程安全 - 覆盖了无效URL、JSON解析失败、无地址数据等多种错误场景
2. 修改continueButton函数,在回调中处理Core Data存储
现在调用loadUrl时,要在闭包里拿到异步返回的结果,再执行Core Data的保存操作:
@IBAction func continueButton(_ sender: Any) { if locationSwitch.isOn { print(location.latitude) print(location.longitude) let url = "https://maps.googleapis.com/maps/api/geocode/json?latlng=\(location.latitude),\(location.longitude)&result_type=locality&key=AIzaSyDI-ZacHyPbLchRhkoaUTDokwj--z_a_jk" // 调用重构后的loadUrl,在回调中处理结果 loadUrl(url: url) { [weak self] cityState, error in guard let self = self else { return } if let cityState = cityState { // 成功获取地址,保存到Core Data CoreDataHandler.saveObject(locationLocality: cityState) print("地址已保存:\(cityState)") } else if let error = error { print("获取地址失败:\(error.localizedDescription)") // 这里可以添加用户提示,比如弹出alert告知错误 } else { // 无结果也无错误的情况,保存空值 CoreDataHandler.saveObject(locationLocality: "") } } } else { // 开关关闭时直接保存空值 CoreDataHandler.saveObject(locationLocality: "") } }
这里的关键细节:
- 使用
[weak self]避免循环引用,防止内存泄漏 - 只有当异步回调拿到结果后,才执行Core Data的保存操作,保证数据有效性
- 覆盖了成功、失败、无结果三种场景的处理逻辑
为什么不能直接返回?
异步操作的本质是「现在发起请求,以后拿到结果」,而函数本身的执行流程是同步的,所以没法等异步任务完成再返回值。闭包回调是Swift中处理异步结果最常用的方式之一,它能让你在结果准备好的时候再执行后续逻辑(比如Core Data存储)。
内容的提问来源于stack exchange,提问作者Patrick Haertel
相关产品推荐
相关产品推荐

