在Realm与SwiftUI中使用@ObservedResults时,如何彻底删除Group关联的Item对象
首先,咱们先搞清楚第一个核心问题:为什么从Group的items列表里移除Item,Item对象还留在数据库中?
这是Realm的设计逻辑决定的:Realm的List类型本质是关联关系(Association),而非拥有关系(Ownership)。也就是说,Group和Item之间是"关联在一起",但Item本身是独立的数据库对象——即使你断开了Group和Item的关联,Item依然可以存在于数据库中(比如可能被其他对象关联,虽然在你的例子里Item的group是LinkingObjects,意味着一个Item只能属于一个Group,但Realm依然不会自动删除它)。
$group.items.remove这个方法的作用仅仅是从Group的items列表中移除Item的引用,而不是删除Item对象本身,这是正常的预期行为。
接下来解决你的第二个问题:如何彻底删除Item,以及你之前代码报错的原因
你遇到的错误Can only delete an object from the Realm it belongs to.,根源在于你手动创建了一个新的Realm实例let realm = try? Realm(),但@ObservedRealmObject修饰的group对象,已经属于Realm SwiftUI包装器自动管理的Realm实例(这个实例和当前视图所在线程绑定)。不同的Realm实例(哪怕是同一个数据库)不能跨实例操作对象,所以会报错。
正确的彻底删除Item的方法
你需要使用Item对象所属的Realm实例来执行删除操作,而@ObservedRealmObject的group对象已经持有了这个实例,直接调用group.realm即可获取。
修改你的deleteItems方法如下:
func deleteItems(at offsets: IndexSet){ // 获取group所属的Realm实例 guard let realm = group.realm else { return } do { try realm.write { // 根据偏移量获取要删除的Item对象 let itemsToDelete = offsets.map { group.items[$0] } // 直接删除Item对象——Realm会自动从所有关联的List/LinkingObjects中移除引用 realm.delete(itemsToDelete) } } catch { print("删除失败:\(error.localizedDescription)") } }
额外优化:级联删除(可选)
如果你希望删除Group时,自动删除所有关联的Item,可以在Group的items属性上设置级联删除策略。修改Group.swift中的代码:
@Persisted var items = RealmSwift.List<Item>(collection: [], deletionPolicy: .cascade)
这样当你调用realm.delete(group)时,所有关联的Item会被自动删除,无需手动遍历。
关键知识点总结
- Realm关联 vs 拥有:
List是关联关系,移除引用≠删除对象;只有调用realm.delete(_:)才会真正删除数据库中的对象。 - 线程绑定:Realm对象和实例都是线程绑定的,必须用对象所属的Realm实例操作它。
- 自动关联清理:删除对象时,Realm会自动清理所有指向该对象的
List和LinkingObjects引用,无需手动移除。
内容的提问来源于stack exchange,提问作者fs_tigre

