核心数据:删除实体的所有实例的最快方法
我正在使用核心数据来本地保留来自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.X和Swift 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)") } }