首页 文章

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

提问于
浏览
358

我正在使用Core Data在本地持久保存Web服务调用的结果 . Web服务返回完整的对象模型,比方说,“汽车” - 可能是大约2000个(我不能让Web服务返回任何小于1或所有汽车 .

下次打开我的应用程序时,我想通过再次为所有汽车调用Web服务来刷新Core Data持久化副本,但为了防止重复,我需要首先清除本地缓存中的所有数据 .

是否有更快的方法来清除托管对象上下文中特定实体的所有实例(例如“CAR”类型的所有实体),或者我是否需要查询它们,然后遍历结果以删除每个,然后保存?

理想情况下,我可以说删除所有实体是Blah的地方 .

22 回答

  • 9

    iOS 9及更高版本:

    iOS 9添加了一个名为 NSBatchDeleteRequest 的新类,它允许您轻松删除与谓词匹配的对象,而无需将它们全部加载到内存中 . 这里's how you' d使用它:

    斯威夫特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];
    

    有关批删除的更多信息,请参见"What's New in Core Data" session from WWDC 2015(从~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
    
  • 0

    更清洁和通用:添加此方法:

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

    重置 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")
            }
        }
    
  • 0

    For 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")
      }
    }
    
  • 0

    Swift:

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

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

  • 31

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

    一个好方法是只添加一个类别到 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
    

    ...你唯一需要的是从app委托中获取managedObjectContext,或者你拥有它的每一个;)

    之后你可以像以下一样使用它:

    [NSManagedObject deleteAllFromEntity:@"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"];
    
  • 1

    延伸Dave Delong的答案 .

    Swift版本也可以处理iOS 9和以前的版本 . 我还介绍了错误处理:

    让appDelegate:AppDelegate = UIApplication.sharedApplication() . 委托为! 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)")
            }
        }
    
  • 16

    iOS 10 and later

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

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

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

    为什么不折叠使用现有缓存接收的数据?否则它不是真正的'刷新',它'重新开始'你也可以删除/删除SQLLite文件并重新开始(假设你也没有持久保存其他数据) .

  • 1

    Swift 4, iOS 12 and Xcode 10 Update

    100% working just cut & paste

    把这个功能放在相关的课堂上
    并在 viewDidLoad() 中调用此函数 self.deleteData()

    或者在任何地方或在功能或按钮下,以便通过单击按钮删除实体中的所有数据,并将"myEntity"替换为您在核心数据中定义的实体

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

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

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

    In 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")
            }
        }
    
  • 0

    In 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)")
        }
    }
    
  • 4

    此代码适用于iOS 9及更低版本

    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()
        }
    
  • 3

    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
        }
    
  • 4

    带有iOS 9 'NSBatchDeleteRequest'的Swift 3解决方案以及作为'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) }
                }
            }
        }
    }
    
  • 24

    使用NSBatchDeleteRequest删除多条记录如果Minimum iOS为9.0 . 如果是后台线程,则执行NSManagedObjectContext save else使用NSFetchRequest来获取记录并删除for循环中的所有记录并保存一次删除完成 .

  • 2

    Swift 4, iOS 10+
    静态函数,可以应用于任何实体删除其所有数据

    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.removeAllObjectsInContext(self.persistentContainer.viewContext)
    
  • 0

    在iOS 11.3和Swift 4.1中

    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 . 如果没有,它将不会在表视图上更新 .

  • 1

    iOS 9.0 and Later :

    NSBatchDeleteRequest 用于删除核心数据中的记录 . 它工作得非常快,从实体中删除所有记录所需的时间更少 . 它在论证中需要 NSFetchRequest . 如果要删除实体中的所有记录,你可以使用它,它适用于我 .

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

相关问题