【问题标题】:Core Data: Quickest way to delete all instances of an entity核心数据:删除实体所有实例的最快方法
【发布时间】:2010-11-25 21:32:38
【问题描述】:

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

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

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

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

【问题讨论】:

  • 你可以使用内存数据库

标签: ios objective-c core-data


【解决方案1】:

NSBatchDeleteRequest Swift 5.5 和 Xcode 13.2

删除 SQLite 持久存储中的对象而不加载到内存中。对持久存储进行的更改不会反映在当前内存中的对象中。

执行批量删除后,删除内存中已从持久存储中删除的所有对象。

下面是一些方便的扩展方法,它们执行batchDeleteRequest

extension NSManagedObject {
    
    private static var entityName: String {
        return String(describing: self)
    }
    
    static func fetchRequest<Self>(
        with predicate: NSPredicate? = nil,
        configureBlock: ((NSFetchRequest<Self>) -> Void)? = nil
    ) -> NSFetchRequest<Self> where Self: NSFetchRequestResult {
        let request = NSFetchRequest<Self>(entityName: entityName)
        request.predicate = predicate
        configureBlock?(request)
        return request
    }
    
    static func batchDelete(with fetchRequest: NSFetchRequest<NSFetchRequestResult>,
                            in context: NSManagedObjectContext) {
        let batchDeteleRequest = NSBatchDeleteRequest(fetchRequest: fetchRequest)
        batchDeteleRequest.resultType = .resultTypeObjectIDs
        do {
            if let fetchResult = try context.execute(batchDeteleRequest) as? NSBatchDeleteResult,
               let deletedManagedObjectIds = fetchResult.result as? [NSManagedObjectID], !deletedManagedObjectIds.isEmpty {
                let changes = [NSDeletedObjectsKey: deletedManagedObjectIds]
                NSManagedObjectContext.mergeChanges(fromRemoteContextSave: changes, into: [context])
            }
        } catch {
            print("Error while executing batchDeleteRequest: \(error.localizedDescription)")
        }
    }
}

示例:我们可以通过传递fetchRequest调用batchDelete静态方法批量删除Entity

class Entity: NSManagedObject {
    @NSManaged var name: String?
    @NSManaged var value: String?
}

extension Entity {
    
    static func executeBatchDelete(in context: NSManagedObjectContext) {
        let predicate = NSPredicate(format: "\(#keyPath(Entity.value)) == %@)", "abc")
        let deleteRequest: NSFetchRequest<NSFetchRequestResult> = Entity.fetchRequest(with: predicate)
        Entity.batchDelete(with: deleteRequest, in: context)
    }
}

【讨论】:

    【解决方案2】:

    以上答案很好地了解了如何删除“汽车”

    但是,我希望这个答案能够挑战方法本身:

    1- SQLite CoreData 是一个关系数据库。在这种情况下,如果没有任何关系,我会建议不要使用 CoreData,而可能使用文件系统,或者将内容保存在内存中。

    2- 在其他示例中,“汽车”实体具有其他关系,因此 CoreData,我建议不要将 2000 辆汽车作为根实体。相反,我会给他们一个父母,比如说“CarsRepository”实体。然后你可以给“汽车”实体一个一对多的关系,当它们被下载时,只需替换关系以指向新的汽车。为关系添加正确的删除规则可确保模型的完整性。

    【讨论】:

      【解决方案3】:

      iOS 9 及更高版本:

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

      斯威夫特 5

      let fetchRequest: NSFetchRequest<NSFetchRequestResult> = NSFetchRequest(entityName: "Car")
      let deleteRequest = NSBatchDeleteRequest(fetchRequest: fetchRequest)
      
      do {
          try myPersistentStoreCoordinator.execute(deleteRequest, with: myContext)
      } catch let error as NSError {
          // TODO: handle the error
      }
      

      目标-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
      

      【讨论】:

      • 我还将配置提取以仅检索 NSManagedObjectID 以减少加载完整对象结构的任何开销。
      • 如何只获取 NSMangagedObjectID 并不明显。使用 [allCars setIncludesPropertyValues:NO]; (不要费心寻找如何为对象 ID 制作 NSPropertyDescription!)
      • 抱歉新手问题:你需要在 for 循环结束后保存上下文吗?例如 [myContext 保存];
      • Core Data 中有什么新工具可以提高效率吗?对于我的应用程序来说,这是一个严重的问题,它已经在移植到 Core Data 的道路上很远。从几个表中的一个表中删除所有 4000 个条目需要几秒钟。用户等待的时间太长了。直接使用 sqlite 的相同请求似乎是瞬间完成的。
      • @DaveDeLong NSBatchDeleteRequest 如何触发 NSFetchedResultsController 委托?我几乎尝试了所有方法,但没有任何反应。
      【解决方案4】:

      Swift 4、iOS 12 和 Xcode 10 更新

      100% 的工作只是剪切和粘贴

      只需将此函数放在相关类中并在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 {
                  if 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)")
          }
      }
      

      【讨论】:

      • 谢谢,但为什么 NSBatchDeleteRequest 概念操作系统不起作用?任何想法。
      • @SureshDurishetti 你在课堂上导入了 CoreData 吗?
      • 是的,添加了 CoreDate。但没有运气。
      • 您忘记在上下文中添加调用 save,添加 context.save() 就可以了
      • 是的,这需要保存上下文,否则不会发生任何变化
      【解决方案5】:

      Swift 4、iOS 10+
      静态函数,可以申请任何实体删除其所有数据

      protocol NSManagedObjectHelper {
      }
      extension NSManagedObject: NSManagedObjectHelper {
      }
      extension NSManagedObjectHelper where Self: NSManagedObject {
          static func removeAllObjectsInContext(_ managedContext: NSManagedObjectContext) {
              let request: NSFetchRequest = NSFetchRequest(entityName: String(describing: self))
              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)
      

      编辑于 20191025:如果我们在同一个项目中使用多个目标,“Self.fetchRequest()”指令可能会导致问题。所以替换为 NSFetchRequest(entityName: String(describing: self))

      【讨论】:

        【解决方案6】:

        没有任何字符串作为实体名称的 OOP 方式 Swift 3+、Xcode 10+

        func batchDelete<T>(in context: NSManagedObjectContext, fetchRequest: NSFetchRequest<T>) throws {
            guard let request = fetchRequest as? NSFetchRequest<NSFetchRequestResult> else {
                throw ErrorService.defaultError
            }
            let batchDeleteRequest = NSBatchDeleteRequest(fetchRequest: request)
            do {
                try context.execute(batchDeleteRequest)
            } catch {
                throw error
            }
        }
        

        然后只需调用 do/catch 块

            let fetchRequest: NSFetchRequest<YourEntity> = YourEntity.fetchRequest()
            do {
                let data = try context.fetch(fetchRequest)
                if data.count > 0 {
                    try self.batchDelete(in: context, fetchRequest: fetchRequest)
                }
            } catch {
                // throw error
            }
        

        【讨论】:

          【解决方案7】:

          快速清除数据库中的所有对象

          func purgeAllData() {
              let uniqueNames = persistentContainer.managedObjectModel.entities.compactMap({ $0.name })
          
              uniqueNames.forEach { (name) in
                let fetchRequest = NSFetchRequest<NSFetchRequestResult>(entityName: name)
                 let batchDeleteRequest = NSBatchDeleteRequest(fetchRequest: fetchRequest)
                   do {
                  try persistentContainer.viewContext.execute(batchDeleteRequest)
                } catch {
                  let nserror = error as NSError
                  fatalError("Unresolved error \(nserror), \(nserror.userInfo)")
                }
             }
           }
          

          【讨论】:

            【解决方案8】:
                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)
                }
            }
            

            【讨论】:

              【解决方案9】:

              iOS 10 及更高版本

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

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

              【讨论】:

              • 感谢您发布您的答案。这对我行得通。但是你不应该只是在这里复制和粘贴你的代码。对于新手来说,不清楚您的 CoreDataStack()DataController() 课程是什么。更新将不胜感激;)
              【解决方案10】:

              iOS 9.0 及更高版本:

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

              【讨论】:

                【解决方案11】:

                此代码适用于 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()
                    }
                

                【讨论】:

                  【解决方案12】:

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

                  您必须在执行后调用重置。如果没有,它不会在 table view 上更新。

                  【讨论】:

                    【解决方案13】:

                    如果最低 iOS 为 9.0,则使用 NSBatchDeleteRequest 删除多条记录。如果是后台线程,则执行 NSManagedObjectContext 保存,否则使用 NSFetchRequest 获取记录并删除 for 循环中的所有记录,并在删除完成后保存。

                    【讨论】:

                      【解决方案14】:

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

                      【讨论】:

                        【解决方案15】:

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

                        【讨论】:

                        • 你也可以使用这个结构: let fetchRequest:NSFetchRequest = YourTable.fetchRequest()
                        【解决方案16】:

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

                        【讨论】:

                        • 别忘了导入CoreData,否则NSFetchRequest & NSBatchDeleteRequest 将不起作用:-)
                        【解决方案17】:

                        带有 iOS 9 'NSBatchDeleteRequest' 的 Swift 3 解决方案并回退到早期的 iO​​S 版本,作为 'NSManagedObjectContext' 的扩展实现。苹果参考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) }
                                    }
                                }
                            }
                        }
                        

                        【讨论】:

                          【解决方案18】:

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

                          【讨论】:

                            【解决方案19】:

                            斯威夫特:

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

                            【讨论】:

                            • 这个答案应该用新的 try/catch 错误处理来更新
                            【解决方案20】:

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

                            【讨论】:

                              【解决方案21】:

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

                              一个好方法是向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"];
                              

                              进一步的优化可能是您删除实体名称的参数并从 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"];
                              

                              【讨论】:

                              • 抱歉,[AppDelegate managedObjectContext] 不一定是“干净的架构”.. ;-)
                              • 好的,没错。它上面的代码基于一个 managedObjectContext。主要的;)在多线程代码中,我通常将应用程序委托的主 MOC 合并到其他人
                              • @DanielRinser 可以是deleteAllFromEntity: inManagedObjectContext:
                              • 是的。最好将 deleteAllFromEntity 方法从类方法更改为对象方法。那么您可以直接在 MOC 实例上调用 deleteAllFromEntity。
                              【解决方案22】:

                              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
                                  }
                              

                              【讨论】:

                                【解决方案23】:

                                扩展 Dave Delong 的答案。

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

                                让 appDelegate: AppDelegate = UIApplication.sharedApplication().delegate as!应用代理

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

                                【讨论】:

                                • 赞成。 ios 9 删除记录的方式真的是 awsm 。
                                【解决方案24】:

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

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

                                【讨论】:

                                  【解决方案25】:

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

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

                                  【讨论】:

                                    【解决方案26】:

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

                                    【讨论】:

                                    • 我刚刚在我当前的项目中尝试了这个,大约有 600 个核心数据对象。当我用级联将它们封装在另一个对象中时,删除大约需要 9.1 秒。如果我使用 Dave 建议的方法,大约需要 8.7 秒才能删除。对我来说没有显着差异。
                                    【解决方案27】:

                                    为什么不将您收到的数据与现有缓存一起折叠起来?否则,它并不是真正的“刷新”,而是“重新开始”,您不妨删除/删除 SQLLite 文件并重新开始(假设您也没有保留其他数据)。

                                    【讨论】:

                                    • 错误的解决方案。如果 Sqlite 数据库中还有其他表,我们显然会丢失所有这些。这更像是针对特定解决方案的 hack,不能考虑用于更大的案例。
                                    猜你喜欢
                                    • 2017-08-12
                                    • 1970-01-01
                                    • 1970-01-01
                                    • 2012-06-22
                                    • 1970-01-01
                                    • 2017-02-16
                                    • 1970-01-01
                                    • 1970-01-01
                                    • 2019-06-10
                                    相关资源
                                    最近更新 更多