修复无网络环境下SwiftData交易数据保存失败问题
实现思路与代码改造方案
核心改造方向
- 将同步的
saveButton改为异步函数,适配isConnected()的异步调用逻辑 - 拆分保存逻辑为两个分支:有网完整保存(包含位置信息)、无网降级保存(跳过逆地理编码,仅保存核心交易数据)
- 修复无网时因
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
相关产品推荐
相关产品推荐

