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

SwiftData一对多关系下代码删除对象崩溃问题求助

问题修复:SwiftData删除Waypoint后崩溃的解决方案

问题根源

崩溃发生在删除Waypoint后尝试更新剩余Waypoint的sequence属性时,核心原因是已被上下文标记删除的Waypoint对象仍被访问其存储属性。SwiftData中,被context.delete()标记删除的对象会立即进入无效状态,此时访问它的sequence等属性会触发内存访问错误。

你的deleteOneWaypoint函数中,先执行了删除操作,之后又从trip.waypoints或查询到的thisTrip.waypoints中遍历对象,这些数组仍持有已删除对象的引用,访问其属性就会导致崩溃。

修复方案

调整操作顺序:先筛选出需要更新序列的有效Waypoint,完成序列更新后再删除目标对象,最后保存上下文,彻底避免访问已删除对象的属性。

修改后的deleteOneWaypoint函数代码:

func deleteOneWaypoint(seq: Int) {
    guard let allWaypoints = trip.waypoints else { return }
    
    // 1. 先筛选出序列大于目标值的Waypoint,更新它们的序列
    let waypointsToUpdate = allWaypoints.filter { $0.sequence > seq }
    waypointsToUpdate.forEach { $0.sequence -= 1 }
    
    // 2. 找到并删除目标Waypoint
    if let waypointToDelete = allWaypoints.first(where: { $0.sequence == seq }) {
        context.delete(waypointToDelete)
    }
    
    // 3. 保存上下文变更
    do {
        try context.save()
    } catch {
        print(error)
    }
}

额外优化建议

  • 移除冗余查询:DetailMapView中无需声明@Query var trips: [Trip],直接使用传入的trip参数即可,避免不必要的数据查询和对象不一致问题。
  • 简化Waypoint数组定义:将Trip中的waypoints改为非可选数组,减少代码中的解包逻辑:
    @Model
    final public class Trip: Identifiable {
        var name: String = "no name"
        @Relationship(.cascade) var waypoints: [Waypoint] = []
    
        init(name: String, waypoints: [Waypoint] = []) {
            self.name = name
            self.waypoints = waypoints
        }
        // 示例数据保持不变
    }
    
  • 有序展示Waypoint:在详情页的列表中按sequence排序展示,确保列表顺序符合预期:
    List {
        ForEach(trip.waypoints.sorted(), id: \.self) { wp in
            // 原有视图内容不变
        }
    }
    

验证效果

修改后点击删除按钮,会先完成剩余Waypoint的序列更新,再删除目标对象,最后保存上下文,不会再触发崩溃,重启应用后数据状态也能保持正确。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.15 03:01:32