Core Data: Quickest way to delete all instances of an entity
我正在使用核心数据本地保存来自Web服务调用的结果。Web服务返回的是"汽车"的完整对象模型——可能有2000辆左右(我不能让Web服务返回少于1辆或全部的汽车)。
下次打开应用程序时,我希望通过再次调用所有汽车的Web服务来刷新核心数据保留副本,但是为了防止重复,我需要首先清除本地缓存中的所有数据。
是否有一种更快的方法来清除托管对象上下文中特定实体的所有实例(例如"car"类型的所有实体),或者我是否需要查询它们调用,然后迭代结果以删除每个实例,然后保存?
理想情况下,我可以说删除实体是blah的所有地方。
iOS 9及更高版本:
ios 9添加了一个名为
1 2 3 4 5 6 7 8 | let fetchRequest = NSFetchRequest(entityName:"Car") let deleteRequest = NSBatchDeleteRequest(fetchRequest: fetchRequest) do { try myPersistentStoreCoordinator.executeRequest(deleteRequest, withContext: myContext) } catch let error as NSError { // TODO: handle the error } |
Objtovi-C
1 2 3 4 5 | NSFetchRequest *request = [[NSFetchRequest alloc] initWithEntityName:@"Car"]; NSBatchDeleteRequest *delete = [[NSBatchDeleteRequest alloc] initWithFetchRequest:request]; NSError *deleteError = nil; [myPersistentStoreCoordinator executeRequest:delete withContext:myContext error:&deleteError]; |
有关批量删除的更多信息,请参阅WWDC 2015的"核心数据的新功能"课程(从~14:10开始)。
iOS 8及更早版本:全部取出并全部删除:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 | NSFetchRequest *allCars = [[NSFetchRequest alloc] init]; [allCars setEntity:[NSEntityDescription entityForName:@"Car" inManagedObjectContext:myContext]]; [allCars setIncludesPropertyValues:NO]; //only fetch the managedObjectID NSError *error = nil; NSArray *cars = [myContext executeFetchRequest:allCars error:&error]; [allCars release]; //error handling goes here for (NSManagedObject *car in cars) { [myContext deleteObject:car]; } NSError *saveError = nil; [myContext save:&saveError]; //more error handling here |
稍微干净一点,通用一点:添加此方法:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 | - (void)deleteAllEntities:(NSString *)nameEntity { NSFetchRequest *fetchRequest = [[NSFetchRequest alloc] initWithEntityName:nameEntity]; [fetchRequest setIncludesPropertyValues:NO]; //only fetch the managedObjectID NSError *error; NSArray *fetchedObjects = [theContext executeFetchRequest:fetchRequest error:&error]; for (NSManagedObject *object in fetchedObjects) { [theContext deleteObject:object]; } error = nil; [theContext save:&error]; } |
重置swift 3中的实体:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 | func resetAllRecords(in entity : String) // entity = Your_Entity_Name { let context = ( UIApplication.shared.delegate as! AppDelegate ).persistentContainer.viewContext let deleteFetch = NSFetchRequest<NSFetchRequestResult>(entityName: entity) let deleteRequest = NSBatchDeleteRequest(fetchRequest: deleteFetch) do { try context.execute(deleteRequest) try context.save() } catch { print ("There was an error") } } |
斯威夫特2:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 | class func clearCoreData(entity:String) { let fetchRequest = NSFetchRequest() fetchRequest.entity = NSEntityDescription.entityForName(entity, inManagedObjectContext: moc!) fetchRequest.includesPropertyValues = false do { if let results = try moc!.executeFetchRequest(fetchRequest) as? [NSManagedObject] { for result in results { moc!.deleteObject(result) } try moc!.save() } } catch { LOG.debug("failed to clear core data") } } |
Swift:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 | let fetchRequest = NSFetchRequest() fetchRequest.entity = NSEntityDescription.entityForName(entityName, inManagedObjectContext: context) fetchRequest.includesPropertyValues = false var error:NSError? if let results = context.executeFetchRequest(fetchRequest, error: &error) as? [NSManagedObject] { for result in results { context.deleteObject(result) } var error:NSError? if context.save(&error) { // do something after save } else if let error = error { println(error.userInfo) } } else if let error = error { println("error: \(error)") } |
这与这里的问题类似,有人建议设置关系删除规则,这样您只需删除一个对象。因此,如果您拥有或可以创建一个与汽车具有对多关系的实体,并在删除较高实体时将删除规则设置为级联,则所有汽车也将被删除。这可能会节省一些处理时间,因为您不必执行装载所有车辆的步骤。在更大的数据集中,这是绝对必要的。
一个好的答案已经发布,这只是一个建议!
一个很好的方法是将一个类别添加到
头文件(如
1 2 3 4 5 | @interface NSManagedObject (Logic) + (void) deleteAllFromEntity:(NSString*) entityName; @end |
代码文件:(例如nsmanagedObject+ext.m)
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 | @implementation NSManagedObject (Logic) + (void) deleteAllFromEntity:(NSString *)entityName { NSManagedObjectContext *managedObjectContext = [AppDelegate managedObjectContext]; NSFetchRequest * allRecords = [[NSFetchRequest alloc] init]; [allRecords setEntity:[NSEntityDescription entityForName:entityName inManagedObjectContext:managedObjectContext]]; [allRecords setIncludesPropertyValues:NO]; NSError * error = nil; NSArray * result = [managedObjectContext executeFetchRequest:allRecords error:&error]; for (NSManagedObject * profile in result) { [managedObjectContext deleteObject:profile]; } NSError *saveError = nil; [managedObjectContext save:&saveError]; } @end |
…唯一需要做的就是从应用程序委托中获取managedObjectContext,或者在每个代理中获取managedObjectContext;)
然后你可以像这样使用它:
1 | [NSManagedObject deleteAllFromEntity:@"EntityName"]; |
进一步的优化可能是您删除了entityname的参数并从clazzname中获取该名称。这将导致使用:
1 | [ClazzName deleteAllFromEntity]; |
更干净的IMPL(作为NSManagedObjectContext的类别):
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 | @implementation NSManagedObjectContext (Logic) - (void) deleteAllFromEntity:(NSString *)entityName { NSFetchRequest * allRecords = [[NSFetchRequest alloc] init]; [allRecords setEntity:[NSEntityDescription entityForName:entityName inManagedObjectContext:self]]; [allRecords setIncludesPropertyValues:NO]; NSError * error = nil; NSArray * result = [self executeFetchRequest:allRecords error:&error]; for (NSManagedObject * profile in result) { [self deleteObject:profile]; } NSError *saveError = nil; [self save:&saveError]; } @end |
然后使用:
1 | [managedObjectContext deleteAllFromEntity:@"EntityName"]; |
iOS 10及更高版本
适用于所有版本。传递实体名并迭代以删除所有条目并保存上下文。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 | func deleteData(entityToFetch: String, completion: @escaping(_ returned: Bool) ->()) { let context = NSManagedObjectContext() context = your managedObjectContext let fetchRequest = NSFetchRequest<NSFetchRequestResult>() fetchRequest.entity = NSEntityDescription.entity(forEntityName: entityToFetch, in: context) fetchRequest.includesPropertyValues = false do { let results = try context.fetch(fetchRequest) as! [NSManagedObject] for result in results { context.delete(result) } try context.save() completion(true) } catch { completion(false) print("fetch error -\(error.localizedDescription)") } } |
Swift 3.x和Swift 4.x,简单方法。只改变你自己
1 2 3 4 5 6 7 8 9 10 11 12 13 14 | let fetchRequest = NSFetchRequest<NSFetchRequestResult>(entityName:"YourTable") fetchRequest.returnsObjectsAsFaults = false do { let results = try context.fetch(fetchRequest) for managedObject in results { let managedObjectData:NSManagedObject = managedObject as! NSManagedObject context.delete(managedObjectData) } } catch let error as NSError { print("Detele all my data in \(entity) error : \(error) \(error.userInfo)") } |
扩大戴夫·德龙的回答。
负责iOS 9和以前版本的Swift版本。我还介绍了以下错误处理:
让AppDelegate:AppDelegate=uiApplication.SharedApplication()。委托为!附加委托
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 | let fetchRequest = NSFetchRequest(entityName:"Car") if #available(iOS 9.0, *) { let delete = NSBatchDeleteRequest(fetchRequest: fetchRequest) do { try appDelegate.persistentStoreCoordinator.executeRequest(delete, withContext: appDelegate.managedObjectContext) } catch let error as NSError { print("Error occured while deleting: \(error)") } } else { // Fallback on earlier versions let carRequest = NSFetchRequest() carRequest.entity = NSEntityDescription.entityForName("Cars", inManagedObjectContext: appDelegate.managedObjectContext) carRequest.includesPropertyValues = false do { let cars: NSArray = try appDelegate.managedObjectContext.executeFetchRequest(carRequest) for car in cars { appDelegate.managedObjectContext.delete(car) } try appDelegate.managedObjectContext.save() } catch let error as NSError { print("Error occured while fetching or saving: \(error)") } } |
swift 4、iOS 12和xcode 10更新
100%工作只需剪切和粘贴
把这个函数放到相关的类中在
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 | func deleteData() { let appDel:AppDelegate = (UIApplication.shared.delegate as! AppDelegate) let context:NSManagedObjectContext = appDel.persistentContainer.viewContext let fetchRequest = NSFetchRequest<NSFetchRequestResult>(entityName:"myEntity") fetchRequest.returnsObjectsAsFaults = false do { let results = try context.fetch(fetchRequest) for managedObject in results { let managedObjectData:NSManagedObject = managedObject as! NSManagedObject context.delete(managedObjectData) } } catch let error as NSError { print("Deleted all my data in myEntity error : \(error) \(error.userInfo)") } } |
为什么不折叠现有缓存接收的数据?否则,它不是真正的"刷新",而是"重新启动",您也可以删除/删除sqllite文件,然后重新启动(假设您没有保存其他数据)。
如果实体包含很多条目,最好的方法是这样,因为这样可以节省内存。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 | - (void)deleteAll:(NSManagedObjectContext *)managedObjectContext entityName:(NSString *)entityName { NSFetchRequest *fetchRequest = [[NSFetchRequest alloc] init]; [managedObjectContext setUndoManager:nil]; NSEntityDescription *entity = [NSEntityDescription entityForName:entityName inManagedObjectContext:managedObjectContext]; [fetchRequest setEntity:entity]; [fetchRequest setIncludesPropertyValues:NO]; [fetchRequest setFetchLimit:100]; // you can change this number if you want NSError *error; NSArray *items = [managedObjectContext executeFetchRequest:fetchRequest error:&error]; while ([items count] > 0) { @autoreleasepool { for (NSManagedObject *item in items) { [managedObjectContext deleteObject:item]; } if (![managedObjectContext save:&error]) { NSLog(@"Error deleting %@ - error:%@",self.entityName, error); } } items = [managedObjectContext executeFetchRequest:fetchRequest error:&error]; } } |
iOS 9.0及更高版本:
1 2 3 4 5 6 7 8 9 10 11 12 13 | let manageObject:NSManagedObjectContext = appDelegateObject.managedObjectContext let fetchRequest = NSFetchRequest(entityName:"EnityName") let deleteRequest = NSBatchDeleteRequest(fetchRequest: fetchRequest) let persistCor:NSPersistentStoreCoordinator = appDelegateObject.persistentObject do { try persistCor.executeRequest(deleteRequest, withContext: manageObject) try manageObject.save() } catch { print(error?.localizedDescription) } |
在斯威夫特3
1 2 3 4 5 6 7 8 9 10 11 12 13 14 | func deleteAllRecords() { //delete all data let context = appDelegate.persistentContainer.viewContext let deleteFetch = NSFetchRequest<NSFetchRequestResult>(entityName:"YourClassName") let deleteRequest = NSBatchDeleteRequest(fetchRequest: deleteFetch) do { try context.execute(deleteRequest) try context.save() } catch { print ("There was an error") } } |
Swift 4,iOS 10版+可应用于任何实体以删除其所有数据的静态函数
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 | protocol NSManagedObjectHelper { } extension NSManagedObject: NSManagedObjectHelper { } extension NSManagedObjectHelper where Self: NSManagedObject { static func removeAllObjectsInContext(_ managedContext: NSManagedObjectContext) { let request: NSFetchRequest = Self.fetchRequest() let deleteRequest = NSBatchDeleteRequest(fetchRequest: request) do { deleteRequest.resultType = .resultTypeObjectIDs//to clear objects from memory let result = try managedContext.execute(deleteRequest) as? NSBatchDeleteResult if let objectIDArray = result?.result as? [NSManagedObjectID] { let changes = [NSDeletedObjectsKey : objectIDArray] /*By calling mergeChangesFromRemoteContextSave, all of the NSManagedObjectContext instances that are referenced will be notified that the list of entities referenced with the NSManagedObjectID array have been deleted and that the objects in memory are stale. This causes the referenced NSManagedObjectContext instances to remove any objects in memory that are loaded which match the NSManagedObjectID instances in the array.*/ NSManagedObjectContext.mergeChanges(fromRemoteContextSave: changes, into: [managedContext]) } try managedContext.save() } catch let error { print(error) } } } |
"Room"是一个实体
1 | Room.removeAllObjectsInContext(self.persistentContainer.viewContext) |
此代码适用于iOS 9及以下版本
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 | class func deleteAllRecords(in entity : String) // entity = Your_Entity_Name { let context = CoreDataStack.getContext() // Note:- Replace your context here with CoreDataStack.getContext() let deleteFetch = NSFetchRequest<NSFetchRequestResult>(entityName: entity) if #available(iOS 9, *) { let deleteRequest = NSBatchDeleteRequest(fetchRequest: deleteFetch) do { try context.execute(deleteRequest) try context.save() } catch { print("There was an error:\(error)") } } else { do{ let deleteRequest = try context.fetch(deleteFetch) for anItem in deleteRequest { context.delete(anItem as! NSManagedObject) } } catch { print("There was an error:\(error)") } } CoreDataStack.saveContext() // Note:- Replace your savecontext here with CoreDataStack.saveContext() } |
戴夫·德隆斯的Swift2.0回答让我崩溃(在iOS 9中)
但这起作用:
1 2 3 4 5 6 7 8 9 10 | let fetchRequest = NSFetchRequest(entityName:"Car") let deleteRequest = NSBatchDeleteRequest(fetchRequest: fetchRequest) do { try managedObjectContext.executeRequest(deleteRequest) try managedObjectContext.save() } catch let error as NSError { // Handle error } |
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 | func deleteAll(entityName: String) { let fetchRequest = NSFetchRequest<NSFetchRequestResult>(entityName: entityName) let deleteRequest = NSBatchDeleteRequest(fetchRequest: fetchRequest) deleteRequest.resultType = .resultTypeObjectIDs guard let context = self.container?.viewContext else { print("error in deleteAll") return } do { let result = try context.execute(deleteRequest) as? NSBatchDeleteResult let objectIDArray = result?.result as? [NSManagedObjectID] let changes: [AnyHashable : Any] = [NSDeletedObjectsKey : objectIDArray as Any] NSManagedObjectContext.mergeChanges(fromRemoteContextSave: changes, into: [context]) } catch { print(error.localizedDescription) } } |
带有iOS 9"nsbatchDeleteRequest"的Swift 3解决方案,并回退到作为"nsManagedObjectContext"扩展实现的早期iOS版本。Apple参考https://developer.apple.com/library/content/featuredarticles/coredata_batch_guide/batchdeletes/batchdeletes.html
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 | extension NSManagedObjectContext { func batchDeleteEntities<T: NSManagedObject>(ofType type: T.Type) throws { let fetchRequest = NSFetchRequest<NSFetchRequestResult>(entityName: String(describing: type.self)) if #available(iOS 9.0, *) { let request = NSBatchDeleteRequest(fetchRequest: fetchRequest) let result = try execute(request) as? NSBatchDeleteResult if let objectIDArray = result?.result as? [NSManagedObjectID] { let changes = [NSDeletedObjectsKey: objectIDArray] NSManagedObjectContext.mergeChanges(fromRemoteContextSave: changes, into: [self]) } } else { fetchRequest.includesPropertyValues = false let results = try fetch(fetchRequest) if let actualResults = results as? [NSManagedObject], !actualResults.isEmpty { actualResults.forEach { delete($0) } } } } } |
如果最小IOS为9.0,请使用nsbatchdeleteRequest删除多个记录。如果是后台线程,则执行nsmanagedObjectContext save,否则使用nsfetchRequest获取记录并删除for循环中的所有记录,删除完成后保存。
在iOS 11.3和Swift 4.1中
1 2 3 4 5 6 7 8 9 10 11 | let fetchRequest = NSFetchRequest<NSFetchRequestResult>(entityName: entityName) let batchDeleteRequest = NSBatchDeleteRequest(fetchRequest: fetchRequest ) batchDeleteRequest.resultType = .resultTypeCount do { let batchDeleteResult = try dataController.viewContext.execute(batchDeleteRequest) as! NSBatchDeleteResult print("The batch delete request has deleted \(batchDeleteResult.result!) records.") dataController.viewContext.reset() // reset managed object context (need it for working) } catch { let updateError = error as NSError print("\(updateError), \(updateError.userInfo)") } |
在执行之后必须调用reset。否则,它将不会在表视图上更新。
在SWIFT 2中:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 | func deleteAllData(entity: String) { let appDelegate = UIApplication.sharedApplication().delegate as! AppDelegate let managedContext = appDelegate.managedObjectContext let fetchRequest = NSFetchRequest(entityName: entity) fetchRequest.returnsObjectsAsFaults = false do { let results = try managedContext.executeFetchRequest(fetchRequest) for managedObject in results { let managedObjectData:NSManagedObject = managedObject as! NSManagedObject managedContext.deleteObject(managedObjectData) } } catch let error as NSError { print("Detele all data in \(entity) error : \(error) \(error.userInfo)") } } |