SwiftData没有触发级联删除的BUG
SwiftData没有触发级联删除的BUG

SwiftData没有触发级联删除的BUG

在SwiftData中删除对象时,可能无法触发级联删除。

问题描述

下面是实际案例的复现:

1、PiggyBank存钱罐对象

@Relationship(deleteRule: .cascade, inverse: \SavingsRecord.piggyBank)
var records: [SavingsRecord]? = []

2、SavingsRecord存取记录对象

@Relationship(inverse: \PiggyBank.records)
var piggyBank: PiggyBank?

两者的关系是一对多的关系,一个PiggyBank对应多个SavingsRecord对象。

3、删除PiggyBank存钱罐

context.delete(data)
try? context.save()

删除PiggyBank存钱罐时,发现关联的SavingsRecord存取记录并没有同步删除,实际上是没有触发级联删除,因此存取记录被保留了下来。

排查过程

后来迭代新版本,发现级联删除的问题得到了解决。使用 GitHub 获取历史版本对比,发现当迭代新版本修改的代码如下:

context.delete(data)

let fetchRequest = FetchDescriptor<PiggyBank>(
    ...
    existingPiggyBanks = try context.fetch(fetchRequest)
    ...
)

try? context.save()

推断是context.fetch(fetchRequest)触发上下文双薪,导致SwiftData刷新上下文状态,处理待删除对象的关系,并触发关系图的重新计算。

下面通过测试进一步验证了这一结论:

context.delete(data)
let _ = try? context.fetch(FetchDescriptor<PiggyBank>())    // 触发上下文刷新
try? context.save()

添加context.fetch代码后,没有触发级联删除的问题得到解决。删除PiggyBank对象时,会同步删除关联的存取记录。

总结

SwiftData在正确配置 @Relationship 关系后,如果在删除SwiftData时,没有触发级联删除,需要使用context.fetch重新触发上下文刷新。

这个问题可能是SwiftData的BUG。

除了使用fetch()触发以外,还可以手动级联删除:

if let records = data.records {
    for record in records {
        context.delete(record)
    }
}
context.delete(data)
try context.save()
   

如果您认为这篇文章给您带来了帮助,您可以在此通过支付宝或者微信打赏网站开发者。

欢迎加入我们的 微信交流群QQ交流群,交流更多精彩内容!
微信交流群二维码 QQ交流群二维码

发表回复

您的电子邮箱地址不会被公开。 必填项已用 * 标注