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

如何在Realm中删除父对象及其全部关联子对象

解决Realm滑动删除时无法删除全部关联子对象的问题

我看了你的代码,发现核心问题在于你手动删除子对象时,错误地用indexPath.row去取exercise列表里的单个元素,而不是处理整个列表里的所有子对象,同时大量的强制解包还可能导致崩溃。下面给你两种可靠的解决方案:

方案一:手动逐层删除所有子对象(适合简单层级模型)

这种方法直观,适合层级不多的场景,我们先获取要删除的Workout对象,然后逐层删除它的所有子对象,最后删除父对象:

override func tableView(_ tableView: UITableView, commit editingStyle: UITableViewCell.EditingStyle, forRowAt indexPath: IndexPath) {
    // 安全校验:确认是删除操作,且数据存在
    guard editingStyle == .delete, let days = days, indexPath.section < days.count, indexPath.row < days[indexPath.section].workout.count else {
        return
    }
    
    let targetWorkout = days[indexPath.section].workout[indexPath.row]
    let targetDay = days[indexPath.section]
    
    do {
        try realm.write {
            // 先删除所有Exercise下的WeightSetsReps对象
            targetWorkout.exercise.forEach { exercise in
                realm.delete(exercise.wsr)
            }
            // 删除当前Workout下的所有Exercise对象
            realm.delete(targetWorkout.exercise)
            // 最后删除Workout对象本身
            realm.delete(targetWorkout)
            
            // 更新表格UI
            tableView.beginUpdates()
            tableView.deleteRows(at: [indexPath], with: .automatic)
            
            // 如果当前Day没有剩余Workout,删除该Day
            if targetDay.workout.isEmpty {
                realm.delete(targetDay)
                tableView.deleteSections(IndexSet(integer: indexPath.section), with: .automatic)
            }
            
            tableView.endUpdates()
        }
    } catch {
        print("删除操作失败:\(error.localizedDescription)")
    }
}

方案二:实现Realm级联删除(适合复杂层级模型)

如果你的数据模型层级比较深,手动逐层删除会很繁琐,我们可以给Realm的Object添加一个扩展,实现自动级联删除所有关联子对象的功能:

第一步:添加级联删除扩展

import RealmSwift

extension Object {
    func cascadeDelete() {
        guard let realm = self.realm else { return }
        
        // 遍历当前对象的所有属性,找到List类型的子对象集合
        for property in objectSchema.properties {
            if property.type == .object, let list = value(forKey: property.name) as? ListBase {
                // 递归删除List中的每个子对象
                for index in 0..<list._rlmArray.count {
                    if let childObject = list._rlmArray[index] as? Object {
                        childObject.cascadeDelete()
                    }
                }
                realm.delete(list)
            }
        }
        
        // 最后删除当前对象本身
        realm.delete(self)
    }
}

第二步:在滑动删除中使用级联删除

override func tableView(_ tableView: UITableView, commit editingStyle: UITableViewCell.EditingStyle, forRowAt indexPath: IndexPath) {
    guard editingStyle == .delete, let days = days, indexPath.section < days.count, indexPath.row < days[indexPath.section].workout.count else {
        return
    }
    
    let targetWorkout = days[indexPath.section].workout[indexPath.row]
    let targetDay = days[indexPath.section]
    
    do {
        try realm.write {
            // 一键级联删除Workout及其所有层级的子对象
            targetWorkout.cascadeDelete()
            
            // 更新表格UI
            tableView.beginUpdates()
            tableView.deleteRows(at: [indexPath], with: .automatic)
            
            // 如果当前Day没有剩余Workout,级联删除该Day
            if targetDay.workout.isEmpty {
                targetDay.cascadeDelete()
                tableView.deleteSections(IndexSet(integer: indexPath.section), with: .automatic)
            }
            
            tableView.endUpdates()
        }
    } catch {
        print("删除操作失败:\(error.localizedDescription)")
    }
}

关键改进点说明:

  1. 安全访问数据:用条件判断替代强制解包,避免数组越界和空值崩溃
  2. 完整删除子对象:方案一中遍历所有Exercise并删除它们的wsr列表,方案二中通过递归自动处理所有层级的子对象
  3. 更优雅的代码:级联删除扩展可以复用在任何Realm对象上,后续新增模型层级也不需要修改删除逻辑

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.05.06 15:57:28