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

Ada*_*mas 373 core-data objective-c ios

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

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

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

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

Dav*_*ong 701

iOS 9及更高版本:

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

斯威夫特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
}
Run Code Online (Sandbox Code Playgroud)

Objective-C的

NSFetchRequest *request = [[NSFetchRequest alloc] initWithEntityName:@"Car"];
NSBatchDeleteRequest *delete = [[NSBatchDeleteRequest alloc] initWithFetchRequest:request];

NSError *deleteError = nil;
[myPersistentStoreCoordinator executeRequest:delete withContext:myContext error:&deleteError];
Run Code Online (Sandbox Code Playgroud)

有关批量删除的更多信息可以在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
Run Code Online (Sandbox Code Playgroud)

  • 我还将配置fetch仅检索NSManagedObjectID以减少在完整对象结构中加载的任何开销. (74认同)
  • 如何仅获取NSMangagedObjectID并不明显..使用[allCars setIncludesPropertyValues:NO]; (并且不要为了如何为对象ID制作NSPropertyDescription而烦恼!) (38认同)
  • Core Data中的任何新工具都能提高效率吗?对于我的应用程序来说,这是一个严重的问题,已经远远地移植到Core Data.它需要几秒钟才能从几个表中的一个表中删除所有4000个条目.这对用户来说太长了等待.与sqlite直接相同的请求似乎是即时的. (6认同)
  • 抱歉新手问题:你是否需要在for循环结束后保存上下文?例如[myContext save]; (5认同)
  • @DaveDeLong NSBatchDeleteRequest如何触发NSFetchedResultsController委托?我几乎尝试了一切,但什么也没发生. (4认同)
  • @David:正如我所写的,CoreData不一定将数据存储在数据库中(这只是一个选项),它也可以将它们存储在XML文件中,并且您当然希望从每个数据库中获得的某些操作不能在XML上轻松执行树.如果您正在处理大量数据,转储数据而不是复杂的对象关系,则直接使用数据库是一个更好的选择; 它将更快,更简单,并提供更强大的操作. (2认同)
  • @Mecki,我同意你的说法,我们不应该将Core Data视为数据库.这并不意味着他们无法添加接受谓词的deleteAll命令.无论SQLite还是XML存储,通过循环单个对象并调用deleteObject来执行这些删除操作是低效的.更不用说性能不好了. (2认同)

roy*_*roy 34

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")
        }
    }
Run Code Online (Sandbox Code Playgroud)


Jon*_*BAB 32

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

- (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];
}
Run Code Online (Sandbox Code Playgroud)


小智 16

对于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")
  }
}
Run Code Online (Sandbox Code Playgroud)


Ixx*_*Ixx 12

迅速:

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)")
}
Run Code Online (Sandbox Code Playgroud)


T. *_*kle 9

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


Erh*_*obl 8

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

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

头文件(例如NSManagedObject+Ext.h)

@interface NSManagedObject (Logic)

+ (void) deleteAllFromEntity:(NSString*) entityName;

@end
Run Code Online (Sandbox Code Playgroud)

代码文件:(例如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
Run Code Online (Sandbox Code Playgroud)

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

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

[NSManagedObject deleteAllFromEntity:@"EntityName"];
Run Code Online (Sandbox Code Playgroud)

进一步优化可能是您删除了实体名称的参数,而是从clazzname获取名称.这将导致使用:

[ClazzName deleteAllFromEntity];
Run Code Online (Sandbox Code Playgroud)

一个更干净的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
Run Code Online (Sandbox Code Playgroud)

用法然后:

[managedObjectContext deleteAllFromEntity:@"EntityName"];
Run Code Online (Sandbox Code Playgroud)


Xco*_*ngi 6

Swift 4,iOS 12和Xcode 10更新

100%工作只是剪切和粘贴

只需将此函数放在相关的类中,
然后在函数或按钮的任何位置或任何位置或任何位置调用此函数self.deleteData()viewDidLoad()

以便通过单击按钮来删除实体中的所有数据,并将“ 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)")
    }
}
Run Code Online (Sandbox Code Playgroud)

  • 您忘了在上下文中添加通话保存,添加context.save()了,您很高兴 (4认同)

jpu*_*til 6

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)
        }
    }
}
Run Code Online (Sandbox Code Playgroud)

“房间”是一个实体

Room.removeAllObjectsInContext(self.persistentContainer.viewContext)
Run Code Online (Sandbox Code Playgroud)

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


Kar*_*mar 5

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)")
        }
    }
Run Code Online (Sandbox Code Playgroud)

  • 感谢您发布您的答案。这对我行得通。但是您不应该只是在此处复制和粘贴您的代码。对于新手来说,不清楚你的 `CoreDataStack()` 或 `DataController()` 类是什么。更新将不胜感激;) (2认同)

Swi*_*per 5

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)")
    }
Run Code Online (Sandbox Code Playgroud)