核心数据:删除实体的所有实例的最快方法

我正在使用核心数据来本地保留来自Web服务调用的结果。 Web服务返回完整的对象模型,比方说,“汽车” – 可能大约有2000个(我不能让Web服务返回任何小于1或所有汽车。

下一次打开我的应用程序时,我想通过再次调用所有Cars的Web Service来刷新Core Data持久拷贝,但是为了防止重复,我需要首先清除本地caching中的所有数据。

是否有更快的方法来清除pipe理对象上下文中的特定实体的所有实例(例如“CAR”types的所有实体),还是需要查询它们的调用,然后遍历结果以删除每个实例,然后保存?

理想情况下,我可以说删除所有的实体是布拉。

iOS 9及更高版本:

iOS 9添加了一个名为NSBatchDeleteRequest的新类,它允许您轻松删除与谓词匹配的对象,而无需将它们全部加载到内存中。 以下是你如何使用它:

Swift 2

 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 } 

Objective-C的

 NSFetchRequest *request = [[NSFetchRequest alloc] initWithEntityName:@"Car"]; NSBatchDeleteRequest *delete = [[NSBatchDeleteRequest alloc] initWithFetchRequest:request]; NSError *deleteError = nil; [myPersistentStoreCoordinator executeRequest:delete withContext:myContext error:&deleteError]; 

有关批量删除的更多信息,请参阅WWDC 2015的“核心数据新增function”会话(从14:10开始)。

iOS 8及更早版本:

取出他们全部并删除他们全部:

 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 

多一点清理和通用:添加此方法:

 - (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 2.0:

 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") } } 

迅速:

 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)") } 

这是一个类似的问题在这里 ,有人build议设置关系删除规则,所以你只需要删除一个对象。 因此,如果您有或可以创build一个与汽车有多对多关系的实体,并且在删除较高的实体时将删除规则设置为级联,则所有汽车也将被删除。 这可以节省一些处理时间,因为您不必执行加载所有车辆的步骤。 在更大的数据集中,这可能是绝对必要的。

已经发布了一个很好的答案,这只是一个build议!

一个好的方法是将一个类别添加到NSManagedObject并实现一个像我一样的方法:

头文件(例如NSManagedObject+Ext.h

 @interface NSManagedObject (Logic) + (void) deleteAllFromEntity:(NSString*) entityName; @end 

代码文件:(例如NSManagedObject + Ext.m)

 @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,或者每个人都拥有它的位置;)

之后你可以使用它:

 [NSManagedObject deleteAllFromEntity:@"EntityName"]; 

一个进一步的优化可能是您删除了entityname的参数,并从clazzname中获取名称。 这将导致使用:

 [ClazzName deleteAllFromEntity]; 

一个更干净的impl(作为类NSManagedObjectContext):

 @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 

用法如下:

 [managedObjectContext deleteAllFromEntity:@"EntityName"]; 

重置Swift 3中的实体:

 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") } } 

扩展Dave Delong的答案。

Swift版本,以及照顾iOS 9和以前的版本。 我也介绍了在这个error handling:

让appDelegate:AppDelegate = UIApplication.sharedApplication()。delegate as! AppDelegate中

  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)") } } 

为什么不折叠您使用现有caching接收的数据? 否则,它不是真正的“刷新”,它是“重新开始”,你也可以删除/删除SQLLite文件,并重新启动(假设你没有保留其他数据)。

iOS 10及更高版本

适用于所有版本。 通过实体名称并迭代以删除所有条目并保存上下文。

 func deleteData(entityToFetch: String, completion: @escaping(_ returned: Bool) ->()) { var context = NSManagedObjectContext() if #available(iOS 10.0, *) { context = your managedObjectContext } else { 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)") } } 

如果实体包含很多条目,最好的方法就是这样,因为它节省了内存

  - (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]; } } 

Dave Delongs的Swift 2.0的答案对我来说是崩溃的(在iOS 9中)

但是这工作:

 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 } 

iOS 9.0和更高版本:

NSBatchDeleteRequest用于删除核心数据中的logging。 它工作速度非常快,并且需要更less的时间从实体中删除所有logging。 它需要参数中的NSFetchRequest。 如果你想从实体中删除所有的logging,你可以使用它,它适用于我。

让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 { } 

Swift 3与iOS 9'NSBatchDeleteRequest'的解决scheme,以及作为'NSManagedObjectContext'扩展实现的早期版本的iOS。 Apple参考资料https://developer.apple.com/library/content/featuredarticles/CoreData_Batch_Guide/BatchDeletes/BatchDeletes.html

 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) } } } } } 

Swift 3.XSwift 4.X ,简单的方法。 只更改YourTable

  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)") } 

在Swift 3.0中

  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 2.0中:

 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)") } }