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

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

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

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


当前回答

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
    }

其他回答

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

迅捷用户界面

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

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

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

上面的答案很好地说明了如何删除“Cars”。

然而,我想用这个答案来挑战这种方法本身:

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

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

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