我使用Core Data在本地持久化Web服务调用的结果。web服务返回完整的对象模型,比如说,“Cars”——可能有2000辆车(我不能让web服务返回小于1辆或ALL辆的任何东西。

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

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

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


当前回答

一个很好的答案已经贴出来了,这只是一个推荐!

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

其他回答

迅捷用户界面

从实体中获取实例,然后循环删除每个实例。

@Environment(\.managedObjectContext) var moc
    
@FetchRequest(sortDescriptors: []) var wizards: FetchedResults<Wizard>

var body: some View {
    VStack {
        List() { }

        Button("Delete all") {
            for wizard in wizards {
                moc.delete(wizard)
            }
            
            if moc.hasChanges {
                try? moc.save()
            }
        }
    }
}

为什么不将接收到的数据与现有缓存一起折叠呢?否则它就不是真正的“刷新”,而是“重新开始”,你也可以删除SQLLite文件并重新开始(假设你没有持久化其他数据)。

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

你必须在执行之后调用重置。如果不是,它将不会在表视图上更新。

快速清除DB中的所有对象:

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

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(description: self))