您知道有什么方法可以删除存储在Core Data中的所有条目吗?我的schema应该保持不变;我只想把它重置为空白。
Edit
我希望以编程方式做到这一点,这样用户就可以基本上按下重置按钮。
您知道有什么方法可以删除存储在Core Data中的所有条目吗?我的schema应该保持不变;我只想把它重置为空白。
Edit
我希望以编程方式做到这一点,这样用户就可以基本上按下重置按钮。
当前回答
Swift 4/5, iOS 9+
重新构建整个CoreData SQLite文件将确保擦除所有数据,因此删除所有实体。只需调用deleteAndRebuild()。
class CoreDataStack {
// Change this
static let datamodelName = "ProjectName"
static let storeType = "sqlite"
static let persistentContainer = NSPersistentContainer(name: datamodelName)
private static let url: URL = {
let url = FileManager.default.urls(for: .applicationSupportDirectory, in: .userDomainMask)[0].appendingPathComponent("\(datamodelName).\(storeType)")
assert(FileManager.default.fileExists(atPath: url.path))
return url
}()
static func loadStores() {
persistentContainer.loadPersistentStores(completionHandler: { (nsPersistentStoreDescription, error) in
if let error = error {
fatalError(error.localizedDescription)
}
})
}
static func deleteAndRebuild() {
try! persistentContainer.persistentStoreCoordinator.destroyPersistentStore(at: url, ofType: storeType, options: nil)
loadStores()
}
}
其他回答
似乎有两种方法:
假设您的核心数据堆栈有一个典型的单例。
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()”是在初始化之后。)
方法一在开发过程中可能更有用。方法二在生产中可能更有用(在相对不常见的情况下,由于某种原因需要擦除所有内容)。
您还可以查找所有实体名称,并按名称删除它们。它是一个较长的版本,但工作得很好,这样你就不必使用持久性存储
- (void)clearCoreData
{
NSError *error;
NSEntityDescription *des = [NSEntityDescription entityForName:@"Any_Entity_Name" inManagedObjectContext:_managedObjectContext];
NSManagedObjectModel *model = [des managedObjectModel];
NSArray *entityNames = [[model entities] valueForKey:@"name"];
for (NSString *entityName in entityNames){
NSFetchRequest *deleteAll = [NSFetchRequest fetchRequestWithEntityName:entityName];
NSArray *matches = [self.database.managedObjectContext executeFetchRequest:deleteAll error:&error];
}
if (matches.count > 0){
for (id obj in matches){
[_managedObjectContext deleteObject:obj];
}
[self.database.managedObjectContext save:&error];
}
}
对于“Any_Entity_Name”,只需要给出任何一个实体的名称,我们只需要找出实体的实体描述。ValueForKey@"name"将返回所有实体名称。最后,别忘了保存。
如果需要删除所有对象且不删除备份文件,可以使用以下方法:
- (void)deleteAllObjectsInContext:(NSManagedObjectContext *)context
usingModel:(NSManagedObjectModel *)model
{
NSArray *entities = model.entities;
for (NSEntityDescription *entityDescription in entities) {
[self deleteAllObjectsWithEntityName:entityDescription.name
inContext:context];
}
}
- (void)deleteAllObjectsWithEntityName:(NSString *)entityName
inContext:(NSManagedObjectContext *)context
{
NSFetchRequest *fetchRequest =
[NSFetchRequest fetchRequestWithEntityName:entityName];
fetchRequest.includesPropertyValues = NO;
fetchRequest.includesSubentities = NO;
NSError *error;
NSArray *items = [context executeFetchRequest:fetchRequest error:&error];
for (NSManagedObject *managedObject in items) {
[context deleteObject:managedObject];
NSLog(@"Deleted %@", entityName);
}
}
注意它可能非常慢(取决于对象图中有多少对象)。
[对请求更新回复的赏金的响应延迟]
回顾之前的答案,
Fetching and deleting all items, as suggested by @Grouchal and others, is still an effective and useful solution. If you have very large data stores then it might be slow, but it still works very well. Simply removing the data store is, as you and @groundhog note, no longer effective. It's obsolete even if you don't use external binary storage because iOS 7 uses WAL mode for SQLite journalling. With WAL mode there may be (potentially large) journal files sitting around for any Core Data persistent store.
But there's a different, similar approach to removing the persistent store that does work. The key is to put your persistent store file in its own sub-directory that doesn't contain anything else. Don't just stick it in the documents directory (or wherever), create a new sub-directory just for the persistent store. The contents of that directory will end up being the persistent store file, the journal files, and the external binary files. If you want to nuke the entire data store, delete that directory and they'll all disappear.
在设置持久化存储时,你会这样做:
NSURL *storeDirectoryURL = [[self applicationDocumentsDirectory] URLByAppendingPathComponent:@"persistent-store"];
if ([[NSFileManager defaultManager] createDirectoryAtURL:storeDirectoryURL
withIntermediateDirectories:NO
attributes:nil
error:nil]) {
NSURL *storeURL = [storeDirectoryURL URLByAppendingPathComponent:@"MyApp.sqlite"];
// continue with storeURL as usual...
}
然后当你想把商店搬走的时候,
[[NSFileManager defaultManager] removeItemAtURL:storeDirectoryURL error:nil];
这将递归地删除自定义子目录和其中的所有Core Data文件。
这只在您没有将持久存储与其他重要数据放在同一个文件夹中时才有效。比如documents目录,其中可能有其他有用的东西。如果这是您的情况,您可以通过查找您想要保留的文件并删除所有其他文件来获得相同的效果。喜欢的东西:
NSString *docsDirectoryPath = [[self applicationDocumentsDirectory] path];
NSArray *docsDirectoryContents = [[NSFileManager defaultManager] contentsOfDirectoryAtPath:docsDirectoryPath error:nil];
for (NSString *docsDirectoryItem in docsDirectoryContents) {
// Look at docsDirectoryItem. If it's something you want to keep, do nothing.
// If it's something you don't recognize, remove it.
}
这种方法可能容易出错。你必须绝对确定你知道你想要保存的每一个文件,否则你可能会删除重要的数据。另一方面,您可以删除外部二进制文件,而不需要知道用于存储它们的文件/目录名称。
接受的答案是正确的,通过NSFileManager删除URL是正确的,但正如在iOS 5+编辑中所述,持久存储不仅仅由一个文件表示。对于SQLite存储,它是*。sqlite, *。Sqlite-shm和*。sqlite-wal……幸运的是,自从iOS 7+我们可以使用方法
[NSPersistentStoreCoordinator + removeUbiquitousContentAndPersistentStoreAtURL选项:错误:):
为了处理删除,代码应该是这样的:
NSPersistentStore *store = ...;
NSError *error;
NSURL *storeURL = store.URL;
NSString *storeName = ...;
NSPersistentStoreCoordinator *storeCoordinator = ...;
[storeCoordinator removePersistentStore:store error:&error];
[NSPersistentStoreCoordinator removeUbiquitousContentAndPersistentStoreAtURL:storeURL.path options:@{NSPersistentStoreUbiquitousContentNameKey: storeName} error:&error];