Core Data删除大量数据的NSBatchDeleteRequest
Core Data删除大量数据的NSBatchDeleteRequest

Core Data删除大量数据的NSBatchDeleteRequest

NSBatchDeleteRequest 是 Core Data 提供的一种高效删除大量数据的机制,特别适合删除 Core Data 存储中成千上万条数据而不影响内存使用。

Core Data删除数据

在 Core Data 中,可以用以下方式删除所有数据:

let results = try context.fetch(fetchRequest)
for object in results {
    context.delete(object)
}

这会把所有数据加载到内存中再删除,非常耗内存,对性能不好。

而使用 NSBatchDeleteRequest,Core Data 会在底层直接对数据库执行 SQL DELETE 操作,不加载任何对象到内存,更快更节省资源。

NSBatchDeleteRequest删除全部数据:

let fetchRequest: NSFetchRequest<NSFetchRequestResult> = 实体名称.fetchRequest()
let deleteRequest = NSBatchDeleteRequest(fetchRequest: fetchRequest)

do {
    try context.execute(deleteRequest)
    context.reset() // 重置 context,释放内存中已删除的对象
} catch {
    print("删除失败: \(error)")
}

例如,删除Yahoo黄金的图表数据:

let fetchRequest: NSFetchRequest<NSFetchRequestResult> = YahooGoldPricePoint.fetchRequest()
let deleteRequest = NSBatchDeleteRequest(fetchRequest: fetchRequest)

do {
    try context.execute(deleteRequest)
    context.reset() // 重置 context,释放内存中已删除的对象
} catch {
    print("删除失败: \(error)")
}

删除条件

如果需要设置删除条件(例如只删除符合某个条件的数据),只需要对 fetchRequest 添加 predicate(谓词)条件,和正常的 NSFetchRequest 一样。

例如,只删除updateTime 小于某个日期的 YahooGoldPricePoint 数据:

let fetchRequest: NSFetchRequest<NSFetchRequestResult> = YahooGoldPricePoint.fetchRequest()

// 设定删除条件,比如只删除一个月前的数据
fetchRequest.predicate = NSPredicate(format: "updateTime < %@", someDate as NSDate)

let deleteRequest = NSBatchDeleteRequest(fetchRequest: fetchRequest)

do {
    try context.execute(deleteRequest)
    context.reset() // 重置 context,防止引用已删除对象
} catch {
    print("批量删除失败:\(error)")
}

fetchRequest 的类型要用 NSFetchRequest<NSFetchRequestResult>,不能是 NSFetchRequest<YahooGoldPricePoint>。

这是因为NSBatchDeleteRequest 处理的是低级别批量删除操作,它直接操作 SQLite,不加载对象进内存,它不认识具体的 YahooGoldPrice 泛型,因此必须写成:

let fetchRequest: NSFetchRequest<NSFetchRequestResult> = YahooGoldPrice.fetchRequest()

注意事项

NSBatchDeleteRequest 默认不会更新 NSManagedObjectContext 中的缓存数据。

如果之后还用 @FetchRequest 或 NSFetchedResultsController,可能会出问题。

解决方法:设置 resultType 为 .resultTypeObjectIDs 并合并变化。

deleteRequest.resultType = .resultTypeObjectIDs

if let result = try context.execute(deleteRequest) as? NSBatchDeleteResult,
   let objectIDs = result.result as? [NSManagedObjectID] {
    let changes = [NSDeletedObjectsKey: objectIDs]
    NSManagedObjectContext.mergeChanges(fromRemoteContextSave: changes, into: [context])
}

当使用context.reset()时,会释放内存中的数据。如果配合插入操作,那么插入操作必须是否使用context.sace()保存。

try context.save()

否则,context.reset()会将未保存的插入数据一并清空。

总结

NSBatchDeleteRequest直接操作数据库,不加载对象到内存,删除效率高。适合批量删除历史记录、清理缓存等操作。

因为不会自动更新内存中的对象,因此需要手动合并或调用context.reset()。

   

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

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

发表回复

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