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

修复无网络环境下SwiftData交易数据保存失败问题

实现思路与代码改造方案

核心改造方向

  1. 将同步的saveButton改为异步函数,适配isConnected()的异步调用逻辑
  2. 拆分保存逻辑为两个分支:有网完整保存(包含位置信息)、无网降级保存(跳过逆地理编码,仅保存核心交易数据)
  3. 修复无网时因getLocation闭包不执行导致的参数未重置问题

具体代码实现

1. 改造saveButton为异步函数

把原同步函数改为async类型,先获取网络状态,再分支执行对应逻辑:

func saveButton() async {
    withAnimation {
        let isConnected = await vm.monitor.isConnected()
        
        if isConnected {
            // 有网:执行带位置的完整保存
            await saveWithFullLocation()
        } else {
            // 无网:执行跳过位置的降级保存
            saveWithoutLocation()
        }
        
        // 统一重置输入参数,避免阻塞下一次操作
        resetEntryParameters()
    }
}

2. 重构位置获取逻辑为Async/Await风格

将原回调式的getLocation改为异步函数,避免嵌套回调:

// 把闭包风格的位置查询转为async/await
func getLocation() async -> CLPlacemark? {
    // 获取设备坐标(假设lm.getLocationCoordinates()是同步方法,异步的话也要改成async)
    let result = lm.getLocationCoordinates()
    entryLat = result.0
    entryLong = result.1
    
    let location = CLLocation(latitude: entryLat, longitude: entryLong)
    
    return await withCheckedContinuation { continuation in
        location.placemark { placemark, error in
            continuation.resume(returning: placemark)
        }
    }
}

// 完整保存逻辑(带位置信息)
private func saveWithFullLocation() async {
    guard let placemark = await getLocation() else {
        // 有网但位置获取失败时,降级保存基础数据
        saveWithoutLocation()
        return
    }
    
    // 解析地址字段
    entryLocCity = placemark.locality
    entryLocState = placemark.administrativeArea
    entryLocCountryL = placemark.countryL
    entryLocCountryS = placemark.countryS
    
    // 插入完整数据到SwiftData
    insertTravelEntry()
}

3. 实现降级保存逻辑

无网或位置获取失败时,仅保存核心交易数据:

// 降级保存逻辑(跳过位置字段)
private func saveWithoutLocation() {
    modelContext.insert(TravelEntries(
        id: UUID(),
        entryDate: entryDT,
        entryMoneyL: Double(moneyS) ?? 0.0,
        entryLat: nil,
        entryLong: nil,
        entryLocCity: nil,
        entryLocState: nil,
        entryLocCountryS: nil,
        entryLocCountryL: nil
    ))
}

// 抽离通用数据插入逻辑(避免代码重复)
private func insertTravelEntry() {
    modelContext.insert(TravelEntries(
        id: UUID(),
        entryDate: entryDT,
        entryMoneyL: Double(moneyS) ?? 0.0,
        entryLat: entryLat,
        entryLong: entryLong,
        entryLocCity: entryLocCity,
        entryLocState: entryLocState,
        entryLocCountryS: entryLocCountryS,
        entryLocCountryL: entryLocCountryL
    ))
}

// 统一重置输入参数
private func resetEntryParameters() {
    self.entryDT = Date()
    self.entryPT = 0
    self.entryCat = 0
    self.entryDsc = ""
    self.moneyS = ""
    // 重置位置相关变量
    self.entryLat = 0.0
    self.entryLong = 0.0
    self.entryLocCity = nil
    self.entryLocState = nil
    self.entryLocCountryL = nil
    self.entryLocCountryS = nil
}

4. 关键注意事项

  • 参数重置时机:将参数重置放在分支逻辑之后,确保无论保存成功/失败,都能清空当前输入状态,不影响下一次操作
  • 容错处理:即使有网,也可能出现定位权限不足、逆地理编码失败的情况,此时自动降级保存基础数据
  • 线程安全:withAnimation确保所有UI和SwiftContext操作在主线程执行,避免线程冲突
  • 网络状态缓存:可以给NWPathMonitor添加@Published变量缓存当前网络状态,避免每次点击都发起异步查询,提升响应速度

额外优化建议

  • 给用户提供状态反馈:无网保存时弹出提示“当前无网络,已保存基础交易数据”
  • 后续同步机制:当网络恢复时,自动补全之前无网保存的交易的位置信息(可在App启动或网络状态变化时触发)

内容的提问来源于stack exchange,提问作者Galen Smith

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.06.15 18:23:14