NSBatchUpdateRequest 是 Core Data 提供的一种高效操作方式,用于在不加载数据到内存中的前提下,批量更新数据库中的记录。它非常适合处理大量数据更新的场景,例如更改成千上万条记录中的某一个字段,而不想逐个实例化对象进行修改。
为什么用 NSBatchUpdateRequest
正常的更新流程是:
1、用 fetchRequest 查询数据。
2、修改每个 NSManagedObject。
3、调用 save() 保存上下文。
但是这种方式在数据量很大时效率低,内存占用高。
而 NSBatchUpdateRequest 会直接在 SQLite 层修改数据,不经过 Core Data 的对象管理系统,因此:
1、速度更快。
2、内存占用更低。
3、不会触发观察者或自动 UI 刷新。
代码示例:
假设有一个实体 Currency,要将所有币种的 amount 设置为 0:
// 1. 创建 FetchRequest(只是为了提取条件)
let fetchRequest: NSFetchRequest<Currency> = Currency.fetchRequest()
fetchRequest.predicate = NSPredicate(format: "amount > %f", 100.0)
// 2. 创建 Batch Update Request
let batchRequest = NSBatchUpdateRequest(entityName: "Currency")
batchRequest.predicate = fetchRequest.predicate // 重用条件
batchRequest.propertiesToUpdate = ["amount": 0.0]
batchRequest.resultType = .updatedObjectsCountResultType
do {
let result = try viewContext.execute(batchRequest) as? NSBatchUpdateResult
print("批量更新 \(result?.result ?? 0) 条记录")
} catch {
print("批量更新失败:\(error)")
}
常用属性
1、entityName:String类型,目标实体名称(初始化时设定)。
2、predicate:NSPredicate?类型,条件筛选器(只更新符合条件的数据)。
3、propertiesToUpdate:[AnyHashable: Any]?类型,要更新的属性和值,键是属性名,值是更新值。
4、resultType:NSBatchUpdateRequestResultType类型,返回结果的类型(见下方)。
5、includesSubentities:Bool(默认 true)类型,是否包含子实体(继承该实体的)。
resultType(结果类型)
resultType 决定了 execute() 返回的内容,枚举值如下:
1、.statusOnlyResultType:无具体数据,仅返回是否成功(默认)。
2、.updatedObjectsCountResultType:NSNumber类型,返回更新的对象数量。
3、.updatedObjectIDsResultType:[NSManagedObjectID]类型,返回更新的对象 ID(需要刷新 UI 时用)。
注意:如果更新后还要刷新 UI,推荐使用 .updatedObjectIDsResultType,然后用 context.refresh(_:mergeChanges:) 来同步数据。
刷新已加载对象(可选)
如果想让 SwiftUI 或其他 UI 及时看到变化,需要使用 NSManagedObjectContext.mergeChanges(fromRemoteContextSave:):
if let objectIDs = result?.result as? [NSManagedObjectID] {
let changes = [NSUpdatedObjectsKey: objectIDs]
NSManagedObjectContext.mergeChanges(fromRemoteContextSave: changes, into: [viewContext])
}
注意事项
1、不会自动更新已加载到内存中的对象(你需要手动刷新或 refetch)。
2、不会触发 NSManagedObjectContext 的 KVO 监听,UI 不会自动刷新。
3、推荐用于后台处理或数据迁移等不需要立即刷新 UI 的情况。