You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

如何等待异步函数loadUrl执行完成后再执行后续代码?

解决Swift异步操作时序问题:确保CoreData等待网络请求完成

咱们先把问题根源说透:loadUrl是异步网络请求,它的回调闭包只会在网络请求完成后才触发,但你当前的代码里,CoreData的savePhotoObject是在主流程同步执行的——这就导致保存操作先于回调里的cityState赋值完成,自然会拿到空值。从你的控制台输出也能清晰看到:After If和CoreData相关的执行逻辑先打印,之后才是回调里的内容,完全符合异步操作的特性。

下面给你两种实用的解决方案:

方案一:将CoreData保存逻辑移到异步回调内部

这是最直接的修复方式,不需要改动loadUrl的现有实现,只需要把依赖cityState的代码放到回调里,确保只有当cityState被正确赋值后才执行保存:

if locationSwitch.isOn == true { 
    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(url: url) { optionalLocation in 
        guard let nonOptionalLocation = optionalLocation else { 
            // 处理location为空的错误情况,比如给cityState设默认值后再保存
            cityState = ""
            CoreDataHandler.savePhotoObject(locationCoordinateLatitude: lat, locationCoordinateLongitude: lng, locationLocality: cityState, dateCreated: date, discription: discriptionBox.text!, photo: selectedImageData!)
            return 
        } 
        // 赋值并执行保存
        cityState = nonOptionalLocation 
        print("cityState: \(cityState)")
        print("Within Func")
        // 把CoreData保存移到这里!
        CoreDataHandler.savePhotoObject(locationCoordinateLatitude: lat, locationCoordinateLongitude: lng, locationLocality: cityState, dateCreated: date, discription: discriptionBox.text!, photo: selectedImageData!)
    } 
    print("Within If") 
} else { 
    lat = 0.0 
    lng = 0.0 
    cityState = "" 
    // else分支也要执行保存
    CoreDataHandler.savePhotoObject(locationCoordinateLatitude: lat, locationCoordinateLongitude: lng, locationLocality: cityState, dateCreated: date, discription: discriptionBox.text!, photo: selectedImageData!)
} 
print("After If") 

这样修改后,无论locationSwitch是否开启,CoreData的保存操作都会在cityState确定后才执行,彻底解决时序问题。

方案二:用Async/Await重构异步逻辑(Swift 5.5+)

如果你使用的是Swift 5.5及以上版本(对应iOS 15+/macOS 12+),可以把loadUrl改成异步函数,用async/await让代码以同步的写法处理异步操作,可读性和维护性都会更好:

第一步:重构loadUrl函数

把原来的闭包回调改成异步返回:

// 先定义解析JSON需要的模型(根据谷歌地理编码API的返回结构调整)
struct GeocodeResponse: Codable {
    let results: [GeocodeResult]
}

struct GeocodeResult: Codable {
    let formattedAddress: String
    
    // 匹配API返回的键名
    enum CodingKeys: String, CodingKey {
        case formattedAddress = "formatted_address"
    }
}

func loadUrl(url: String) async -> String? {
    guard let url = URL(string: url) else { return nil }
    do {
        let (data, _) = try await URLSession.shared.data(from: url)
        let result = try JSONDecoder().decode(GeocodeResponse.self, from: data)
        return result.results.first?.formattedAddress
    } catch {
        print("请求或解析错误:\(error)")
        return nil
    }
}

第二步:调用异步函数并等待结果

在调用处用await等待loadUrl完成,之后再执行CoreData保存:

Task { // 在异步任务中执行await操作
    if locationSwitch.isOn == true { 
        let url = "https://maps.googleapis.com/maps/api/geocode/json?latlng=\(location.latitude),\(location.longitude)&result_type=locality&key=AIzaSyDI-ZacHyPbLchRhkoaUTDokwj--z_a_jk" 
        let optionalLocation = await loadUrl(url: url)
        guard let nonOptionalLocation = optionalLocation else { 
            cityState = ""
            CoreDataHandler.savePhotoObject(locationCoordinateLatitude: lat, locationCoordinateLongitude: lng, locationLocality: cityState, dateCreated: date, discription: discriptionBox.text!, photo: selectedImageData!)
            return 
        } 
        cityState = nonOptionalLocation 
        print("cityState: \(cityState)")
    } else { 
        lat = 0.0 
        lng = 0.0 
        cityState = "" 
    }
    // 统一执行保存操作
    CoreDataHandler.savePhotoObject(locationCoordinateLatitude: lat, locationCoordinateLongitude: lng, locationLocality: cityState, dateCreated: date, discription: discriptionBox.text!, photo: selectedImageData!)
    print("After If")
}

这种方式避免了嵌套回调的混乱,代码逻辑更线性,也更容易排查问题。

总结一下:方案一适合快速修复现有代码,方案二更适合长期维护的现代Swift项目,你可以根据自己的项目版本和需求选择。

内容的提问来源于stack exchange,提问作者Patrick Haertel

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.05.29 09:07:44