🔑

如何在 SwiftData 中批量删除数据

核心摘要:想在 SwiftData 中高效删除成千上万条数据?无需遍历 ModelContext,直接使用 delete(model:where:) API 即可绕过对象创建开销,秒级完成数据清理。

问题

在 Core Data 中,批量操作是一个利器。它让开发者绕过上下文(Context)直接操作持久化存储(Persistent Store),从而大幅提高数据操作的性能。那么在 SwiftData 中是否有类似的能力呢?

什么是批量操作

在 SwiftData 和 Core Data 中,绝大多数常规数据操作都是通过上下文(ModelContext)进行的。上下文负责将持久化数据转换成开发者声明的 Swift 类型实例,同时维护对象图(Object Graph)和数据关系。

虽然功能强大,但上下文的这些机制(如实例化对象、维护关系)会带来显著的内存和 CPU 开销。当需要处理大量数据时,逐个加载并删除会导致严重的性能下降甚至 UI 卡顿。

批量操作的核心在于绕过上下文,直接将指令发送给持久化处理层,从而大幅提高执行速度。

使用 delete 方法进行批量删除

SwiftData 提供了一个比 Core Data 更加现代且类型安全的批量删除 API。

Swift
func delete<T>(
    model: T.Type,
    where predicate: Predicate<T>? = nil, // 筛选条件,nil 表示删除所有
    includeSubclasses: Bool = true // 是否包含子类数据
) throws where T : PersistentModel

1. 删除特定类型的所有数据

开发者可以使用如下代码瞬间清空 Item 表中的所有数据:

Swift
// 删除 Item 类型的所有数据
try? modelContext.delete(model: Item.self)
// 必须保存上下文才能触发生效
try? modelContext.save()

注意:与常规的单对象删除 modelContext.delete(_ model: T) 不同,批量删除必须在执行 save() 后才会真正应用到数据库

得益于 SwiftData 内置的 Persistent History Tracking 支持,批量删除执行后,内存中的上下文会自动感知变化,无需手动处理。

2. 按条件批量删除

如果需要删除符合特定条件的数据,只需结合 Swift 宏 #Predicate 即可:

Swift
// 删除所有名字为 "abc" 的 SubItem
let predicate = #Predicate<SubItem> {
    $0.name == "abc"
}

try? modelContext.delete(model: SubItem.self, where: predicate)
try? modelContext.save()

与 Core Data 一样,SwiftData 的批量删除会自动处理级联删除(Cascade Deletion) 规则。如果 Item 与其他模型存在关联且设置了删除规则,相关数据也会被一并清理。

3. 处理数据继承

SwiftData 支持模型继承。在删除父类数据时,默认会同时删除其子类的数据。如果只想删除父类本身的数据(在某些特殊的数据模型设计中),可以将 includeSubclasses 设置为 false

Swift
@Model
class Item {
    var timestamp: Date
    
    init(timestamp: Date) {
        self.timestamp = timestamp
    }
}

@available(iOS 26, *)
@Model
final class SubItem: Item { // Item 的子类型
    var name: String

    init(name: String) {
        self.name = name
        super.init(timestamp: .now)
    }
}

// 仅删除 Item 表中的基础记录,保留 SubItem 类型的数据
try? modelContext.delete(model: Item.self, includeSubclasses: false) 
try? modelContext.save()

局限性:批量添加与更新

虽然 Swift 6 和 iOS 26 带来了诸多改进,但截止目前,SwiftData 原生依然仅支持批量删除,尚未提供原生的批量更新(Batch Update)和批量插入(Batch Insert)API。

由于 SwiftData 和 Core Data 共享完全一致的底层存储结构(SQLite),如果你的应用对批量更新或插入有极高的性能要求,可以通过混合使用 Core Data 的 NSBatchUpdateRequestNSBatchInsertRequest 来实现。

具体实现方案可参考:如何在 Core Data 中进行批量操作

相关提示

订阅 Fatbobman 周报

每周精选 Swift 与 SwiftUI 开发技巧,加入众多开发者的行列。

立即订阅