您知道有什么方法可以删除存储在Core Data中的所有条目吗?我的schema应该保持不变;我只想把它重置为空白。


Edit

我希望以编程方式做到这一点,这样用户就可以基本上按下重置按钮。


当前回答

似乎有两种方法:

假设您的核心数据堆栈有一个典型的单例。

import CoreData
public let core = Core.shared
public final class Core {
    static let shared = Core()
    var container: NSPersistentContainer!
    private init() {
        container = NSPersistentContainer(name: "stuff")
        //deleteSql()
        container.loadPersistentStores { storeDescription, error in
            if let error = error { print("Error loading... \(error)") }
        }
        //deleteAll()
    }
    
    func saveContext() { // typical save helper
        if container.viewContext.hasChanges {
            do { try container.viewContext.save()
            } catch { print("Error saving... \(error)") }
        }
    }
    

然后……

    func deleteSql() {
        let url = FileManager.default.urls(
           for: .applicationSupportDirectory,
           in: .userDomainMask)[0].appendingPathComponent( "stuff.sqlite" )
        
        guard FileManager.default.fileExists(atPath: url.path) else {
            print("nothing to delete!")
            return
        }
        
        do {
            try container.persistentStoreCoordinator.destroyPersistentStore(
                at: url, ofType: "sqlite", options: nil)
            print("totally scorched the sql file. you DO now have to LOAD again")
        }
        catch {
            print("there was no sql file there!")
        }
    }
    
    func deleteAll() { // courtesy @Politta
        for e in container.persistentStoreCoordinator.managedObjectModel.entities {
            let r = NSBatchDeleteRequest(
              fetchRequest: NSFetchRequest(entityName: e.name ?? ""))
            let _ = try? container.viewContext.execute(r)
        }
        saveContext()
        print("conventionally deleted everything from within core data. carry on")
    }
}

.

1. 焦化SQL文件

感谢优秀的@J。能源部的答案。您完全销毁了sql文件。

你必须这样做

在加载核心数据之前,即在创建容器之后,但是 在真正载入商店之前。)

(注意示例代码“//deleteSql()”就在初始化之前。)

2. 逐个删除核心数据中的所有内容

感谢精彩的@Politta回答。一旦core data启动并运行,就可以随时执行此操作。

(注意示例代码“//deleteAll()”是在初始化之后。)

方法一在开发过程中可能更有用。方法二在生产中可能更有用(在相对不常见的情况下,由于某种原因需要擦除所有内容)。

其他回答

下面是一个稍微简化的版本,减少了对AppDelegate self的调用,并且去掉了排名最高的答案中的最后一点代码。此外,我得到了一个错误“对象的持久存储无法从这个NSManagedObjectContext的协调器”,所以只需要添加回来。

NSPersistentStoreCoordinator *storeCoordinator = [self persistentStoreCoordinator];
NSPersistentStore *store = [[storeCoordinator persistentStores] lastObject];
NSURL *storeURL = [[self applicationDocumentsDirectory] URLByAppendingPathComponent:@"dataModel"];
NSError *error;

[storeCoordinator removePersistentStore:store error:&error];
[[NSFileManager defaultManager] removeItemAtPath:storeURL.path error:&error];

[_persistentStoreCoordinator addPersistentStoreWithType:NSSQLiteStoreType configuration:nil URL:storeURL options:nil error:&error];

if (storeCoordinator != nil) {
    _managedObjectContext = [[NSManagedObjectContext alloc] init];
    [_managedObjectContext setPersistentStoreCoordinator:storeCoordinator];
}

你可以删除SQLite文件-但我选择通过一个函数单独清除表来做到这一点:

- (void) deleteAllObjects: (NSString *) entityDescription  {
    NSFetchRequest *fetchRequest = [[NSFetchRequest alloc] init];
    NSEntityDescription *entity = [NSEntityDescription entityForName:entityDescription inManagedObjectContext:_managedObjectContext];
    [fetchRequest setEntity:entity];

    NSError *error;
    NSArray *items = [_managedObjectContext executeFetchRequest:fetchRequest error:&error];
    [fetchRequest release];


    for (NSManagedObject *managedObject in items) {
        [_managedObjectContext deleteObject:managedObject];
        DLog(@"%@ object deleted",entityDescription);
    }
    if (![_managedObjectContext save:&error]) {
        DLog(@"Error deleting %@ - error:%@",entityDescription,error);
    }

}

我选择逐表执行的原因是,它使我在编程时确认删除表的内容是合理的,并且没有我宁愿保留的数据。

这样做会比仅仅删除文件慢得多,如果我这个方法花费太长时间,我将更改为文件删除。

iOS 10 + Swift 3解决方案:

func clearCoreDataStore() {
    let delegate = UIApplication.shared.delegate as! AppDelegate
    let context = delegate.persistentContainer.viewContext

    for i in 0...delegate.persistentContainer.managedObjectModel.entities.count-1 {
        let entity = delegate.persistentContainer.managedObjectModel.entities[i]

        do {
            let query = NSFetchRequest<NSFetchRequestResult>(entityName: entity.name!)
            let deleterequest = NSBatchDeleteRequest(fetchRequest: query)
            try context.execute(deleterequest)
            try context.save()

        } catch let error as NSError {
            print("Error: \(error.localizedDescription)")
            abort()
        }
    }
}

遍历所有核心数据实体并清除它们

您仍然可以使用NSFileManager:removeItemAtPath::方法以编程方式删除该文件。

NSPersistentStore *store = ...;
NSError *error;
NSURL *storeURL = store.URL;
NSPersistentStoreCoordinator *storeCoordinator = ...;
[storeCoordinator removePersistentStore:store error:&error];
[[NSFileManager defaultManager] removeItemAtPath:storeURL.path error:&error];

然后,只需将持久存储添加回去,以确保正确地重新创建它。

遍历每个实体的编程方式既慢又容易出错。这样做的用途是如果您想删除一些实体而不是其他实体。然而,您仍然需要确保您保留了引用完整性,否则您将无法持久您的更改。

仅仅删除存储并重新创建它既快速又安全,当然可以在运行时以编程方式完成。

iOS5+更新

随着iOS 5和OS X 10.7引入外部二进制存储(allowsExternalBinaryDataStorage或Store in external Record File),简单地删除由storeurl指向的文件是不够的。你会留下外部记录文件。由于这些外部记录文件的命名方案不是公开的,所以我还没有一个通用的解决方案。- 12年5月8日23:00

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

func deleteData(entityToFetch: String, completion: @escaping(_ returned: Bool) ->()) {
    var context = NSManagedObjectContext()
    if #available(iOS 10.0, *) {
        context = self.persistentContainer.viewContext
    } else {
        context = self.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)")
    }
}