删除/重置核心数据中的所有条目?


235

您是否知道删除存储在核心数据中的所有条目的任何方法?我的架构应该保持不变;我只想将其重置为空白。


编辑

我正在寻找以编程方式执行此操作,以便用户可以基本上按一下reset按钮。


6
下面的许多答案都是过时的。使用NSBatchDeleteRequeststackoverflow.com/a/31961330/3681880
Suragch

Answers:


198

您仍然可以使用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或存储在外部记录文件中),仅删除storeURLs指向的文件是不够的。您将留下外部记录文件。由于这些外部记录文件的命名方案不是公开的,所以我还没有一个通用的解决方案。– 2012年5月8日an0 23:00


1
这可能是可靠性的最佳解决方案。:如果我想删除一些而不是全部的数据,我会用这个stackoverflow.com/questions/1077810/...
迈克尔Grinich

12
我知道如何正确检索storeCoordinator。但是我不知道如何获取persistentStore。因此,您可以举一个正确的例子,而不是仅仅:NSPersistentStore * store = ...;
Pascal Klein

11
[[NSFileManager defaultManager] removeItemAtURL:storeURL错误:&error]更好。
an0

3
@Pascal如果可以获取商店协调器,则可以通过persistentStores属性访问其所有持久性存储。
Mihai Damian 2012年

2
示例代码,包括如何在此处重新创建新的空商店:stackoverflow.com/a/8467628
Joshua C. Lerner

140

您可以删除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);
    }

}

我选择逐表进行处理的原因是,这使我在进行编程时确认删除表的内容是明智的,并且没有要保留的数据。

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


很好的解决方案。谢谢。什么是DLog()?
Michael Grinich,2009年

是的-抱歉,这是我使用的特殊功能,仅在构建为DEBUG构建时才使用NSLog-只需替换为NSLog。
Grouchal,2009年

6
您可以在此处看到DLog的实现:cimgf.com/2009/01/24/dropping-nslog-in-release-builds
Matt Long 2009年

3
这对我来说很好。但是为了使其运行更快,是否有一种方法可以使用一个命令删除某个实体的所有对象?像在SQL中一样,您可以执行类似DROP TABLE entity_name的操作。我不想删除整个SQL文件,因为我只想删除特定实体的所有对象,而不是其他实体。
ma11hew28 2010年

8
使用NSDictionary * allEntities = _managedObjectModel.entitiesByName; 获取模型中的所有实体,然后可以遍历此NSDictionary中的键以清除商店中的所有实体。
adam0101

60

更新的iOS 10+解决方案

使用NSBatchDeleteRequest以删除实体的所有对象,而无需将其加载到内存或迭代通过他们。

// create the delete request for the specified entity
let fetchRequest: NSFetchRequest<NSFetchRequestResult> = MyEntity.fetchRequest()
let deleteRequest = NSBatchDeleteRequest(fetchRequest: fetchRequest)

// get reference to the persistent container
let persistentContainer = (UIApplication.shared.delegate as! AppDelegate).persistentContainer

// perform the delete
do {
    try persistentContainer.viewContext.execute(deleteRequest)
} catch let error as NSError {
    print(error)
}

此代码已针对iOS 10和Swift 3更新。如果您需要支持iOS 9,请参阅此问题

资料来源:


3
我会将整个方块放在moc.performBlockAndWait({ () -> Void in...内})
SwiftArchitect

2
确保您看到为什么在应用程序重新启动或我两次执行NSBatchDeleteRequest之前为什么不删除条目?长话来说,如果将实体加载到内存中,上述代码是不够的
Honey

38

我编写了clearStores遍历每个存储区并从协调程序和文件系统中删除它的方法(撇开错误处理):

NSArray *stores = [persistentStoreCoordinator persistentStores];

for(NSPersistentStore *store in stores) {
    [persistentStoreCoordinator removePersistentStore:store error:nil];
    [[NSFileManager defaultManager] removeItemAtPath:store.URL.path error:nil];
}

[persistentStoreCoordinator release], persistentStoreCoordinator = nil;

该方法位于一个coreDataHelper类中,该类负责(除其他事项外)在null时创建persistentStore。


“选择器'persistentStores'的未知类方法”
Aviram Netanel 2015年

27

我从HomeViewController类的Button事件中的核心数据中删除了所有数据:这篇文章对我有很大帮助,我认为我会有所作为。

-(IBAction)buttonReset:(id)sender
{
    NSLog(@"buttonReset Pressed");

    //Erase the persistent store from coordinator and also file manager.
    NSPersistentStore *store = [self.persistentStoreCoordinator.persistentStores lastObject];
    NSError *error = nil;
    NSURL *storeURL = store.URL;
    [self.persistentStoreCoordinator removePersistentStore:store error:&error];
    [[NSFileManager defaultManager] removeItemAtURL:storeURL error:&error];


    NSLog(@"Data Reset");

    //Make new persistent store for future saves   (Taken From Above Answer)
    if (![self.persistentStoreCoordinator addPersistentStoreWithType:NSSQLiteStoreType configuration:nil URL:storeURL options:nil error:&error]) {
        // do something with the error
    }

}

请注意,为了调用self.persistentStoreCoordinator,我在Home View Controller中声明了一个属性。(不必担心我用于保存和加载的managedObjectContext。)

@property (nonatomic, retain) NSManagedObjectContext        *   managedObjectContext;
@property (nonatomic, retain) NSPersistentStoreCoordinator  *   persistentStoreCoordinator;

然后在下面的AppDelegate ApplicationDidFinishLaunching中创建HomeViewController,我有:

homeViewController = [[HomeViewController alloc] initWithNibName:@"HomeViewController" bundle:nil];
homeViewController.managedObjectContext = self.managedObjectContext;
homeViewController.persistentStoreCoordinator = self.persistentStoreCoordinator;

@ayteat,这对您有用吗?对我来说它不工作,请看看这个stackoverflow.com/questions/14646595/...
兰吉特

1
除了使用“ AppDelegate * ad = [[UIApplication sharedApplication]委托];”之外,这是答案。并用广告代替自我。并且不要复制代码的最后两位
Cescy 2014年

1
为什么不在managedObjectContext上调用reset?如果您对ManagedObject有很强的引用怎么办?
Parag Bafna 2015年

@ParagBafna是的,上面的代码示例假定没有对托管对象的强引用。如果有的话,应该查看在managedObjectContext上调用“重置”并取消引用您拥有的所有托管对象。
atreat 2015年

嘿,谢谢。另外,有什么办法可以在应用升级时做到这一点吗?确切地说,我的要求是当我滚动我们的下一版应用程序时,即当用户从appStore更新其应用程序时,应删除n个sqlite文件的核心数据并将其重新初始化为空白。我想出了一种方法,可以使用NSUserDefaults中的Bool值来检测应用程序首次启动事件,并在应用程序委托的didfinishLaunchingWithOptions中检查该值,但不了解如何清除所有这些内容。由于没有按钮,因此应用程序委托没有像上面一样检测到我的“ persistentStore”以清除它。有帮助吗?
Tejas

19

MagicalRecord使此操作非常容易。

[MyCoreDataObject MR_truncateAll];

16
这很酷,但是离题,因为我指定了CoreData解决方案
Michael Grinich

8
Active Record Fetching 核心数据解决方案。
casademora 2011年

7
但是这样的答案超出了问题的范围。没有理由假设他想使用addt'l框架来执行此操作。
jpswain

我认为这不能解决问题。这是从一个实体而非所有实体中删除条目的好方法...!您如何枚举模型中的所有实体并将其发送MR_truncateAll
fatuhoku

查看MR_truncateAll的源代码-它获取所有对象但不获取它们的属性(因为我们打算丢弃NSMO),然后遍历指定实体的对象并删除它们。github.com/magicalpanda/MagicalRecord/blob/master/MagicalRecord/…–
1in9ui5t

19

iOS9 +,Swift 2

删除所有实体中的所有对象

func clearCoreDataStore() {
    let entities = managedObjectModel.entities
    for entity in entities {
        let fetchRequest = NSFetchRequest(entityName: entity.name!)
        let deleteReqest = NSBatchDeleteRequest(fetchRequest: fetchRequest)
        do {
            try context.executeRequest(deleteReqest)
        } catch {
            print(error)
        }
    }
}

1
确保您看到为什么在应用程序重新启动或我两次执行NSBatchDeleteRequest之前为什么不删除条目?长话来说,如果将实体加载到内存中,上述代码是不够的
Honey

13

[针对悬赏要求新答案的最新答案]

查看先前的答案,

  • @Grouchal和其他人建议,获取和删除所有项目仍然是一种有效和有用的解决方案。如果您有非常大的数据存储,那么它可能会很慢,但是仍然可以很好地工作。
  • 如您和@groundhog所述,仅删除数据存储不再有效。即使您不使用外部二进制存储,它也已过时,因为iOS 7使用WAL模式进行SQLite日志记录。使用WAL模式时,任何Core Data持久性存储都可能存在(可能很大)日志文件。

但是,有另一种类似的方法可以删除有效的持久性存储。关键是将持久性存储文件放在其自己的不包含其他任何内容的子目录中。不要只是将其粘贴在documents目录(或任何位置)中,而是为持久性存储创建一个新的子目录。该目录的内容最终将是持久性存储文件,日记文件和外部二进制文件。如果您想删除整个数据存储区,请删除该目录,它们都将消失。

在设置持久性存储时,您将执行以下操作:

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

这种方法可能容易出错。您必须绝对确定自己知道要保留的每个文件,否则可能会删除重要数据。另一方面,您可以删除外部二进制文件,而无需实际知道用于存储它们的文件/目录名称。


如果您担心wal文件,请将其禁用
onmyway133

11

这是清除核心数据的组合解决方案。

- (void)deleteAllObjectsInCoreData
{
    NSArray *allEntities = self.managedObjectModel.entities;
    for (NSEntityDescription *entityDescription in allEntities)
    {
        NSFetchRequest *fetchRequest = [[NSFetchRequest alloc] init];
        [fetchRequest setEntity:entityDescription];

        fetchRequest.includesPropertyValues = NO;
        fetchRequest.includesSubentities = NO;

        NSError *error;
        NSArray *items = [self.managedObjectContext executeFetchRequest:fetchRequest error:&error];

        if (error) {
                NSLog(@"Error requesting items from Core Data: %@", [error localizedDescription]);
            }

        for (NSManagedObject *managedObject in items) {
            [self.managedObjectContext deleteObject:managedObject];
        }

        if (![self.managedObjectContext save:&error]) {
            NSLog(@"Error deleting %@ - error:%@", entityDescription, [error localizedDescription]);
        }
    }  
}

10

如果要删除所有对象,并且不想删除备份文件,则可以使用以下方法:

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

请注意,它可能非常慢(取决于对象图中有多少个对象)。


应用程序更新时如何删除较旧的数据(例如,从一个表中我要清除数据的三个表)
Madan Mohan

6

如果您要执行“删除所有对象”路由(这比拆除“核心数据”堆栈要简单得多,但性能较低),那么这是一个更好的实现:

- (void)deleteAllManagedObjectsInModel:(NSManagedObjectModel *)managedObjectModel context:(NSManagedObjectContext *)managedObjectContext
{
    NSBlockOperation *operation = [NSBlockOperation blockOperationWithBlock:^{
        [managedObjectContext performBlockAndWait:^{
            for (NSEntityDescription *entity in managedObjectModel) {
                NSFetchRequest *fetchRequest = [NSFetchRequest new];
                [fetchRequest setEntity:entity];
                [fetchRequest setIncludesSubentities:NO];
                NSArray *objects = [managedObjectContext executeFetchRequest:fetchRequest error:nil];
                for (NSManagedObject *managedObject in objects) {
                    [managedObjectContext deleteObject:managedObject];
                }            
            }

            [managedObjectContext save:nil];
        }];
    }];
    [operation setCompletionBlock:^{
        // Do stuff once the truncation is complete
    }];
    [operation start];
}

此实现利用NSOperation执行主线程的删除并在完成时通知。您可能希望在完成块内发出通知或其他通知,以将状态冒泡回到主线程。


请注意,您的NSManagedObjectContext必须像NSManagedObjectContext *context = [[NSManagedObjectContext alloc] initWithConcurrencyType:NSPrivateQueueConcurrencyType];使用该方法一样进行初始化,否则会出现错误:Can only use -performBlock: on an NSManagedObjectContext that was created with a queue.
2015年

6

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

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


4

感谢您的帖子。我遵循它,它为我工作。但我有另一个未在任何答复中提及的问题。所以我不确定是否只是我。

无论如何,以为我会在这里发布问题以及解决问题的方式。

我在数据库中有几条记录,我想在将新数据写入db之前清除所有内容,因此我做了包括

[[NSFileManager defaultManager] removeItemAtURL:storeURL error:&error]; 

然后用来managedObjectContext访问数据库(现在应该是空的),数据仍然存在。一段时间后故障排除,我发现我需要重置managedObjectContextmanagedObjectmanagedObjectModelpersistentStoreCoordinator,以前我用managedObjectContext访问dabase。现在,我有一个干净的数据库要写入。


因此,重置managedObjectContext,managedObject,managedObjectModel和persistentStoreCoordinator会将包含数据库的文件删除后放回去吗?
Daniel Brower

4

这是一个稍微简化的版本,对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];
}

4

快速解决方案:

class func deleteAllManagedObjects() {

        let modelURL = NSBundle.mainBundle().URLForResource("some string", withExtension: "mom")
        let mom = NSManagedObjectModel(contentsOfURL: modelURL)

        for entityName in mom.entitiesByName.keys {
            let fr = NSFetchRequest(entityName: entityName as String)
            let a = Utility.managedObjectContext().executeFetchRequest(fr, error: nil) as [NSManagedObject]
            for mo in a {
                Utility.managedObjectContext().deleteObject(mo)
            }
        }

        Utility.managedObjectContext().save(nil)
    }

快速行动2let modelURL = NSBundle.mainBundle().URLForResource("some string", withExtension: "momd")!
Saorikido

3

作为将搜索保存到其他位置的快速参考-删除后重新创建持久性存储可以使用以下方法完成:

if (![persistentStoreCoordinator addPersistentStoreWithType:NSSQLiteStoreType configuration:nil URL:storeURL options:nil error:&error]) {
// do something with the error
}

我尝试了您的代码,但是xcode在此行上引发了异常,因此您必须说些什么。
兰吉特(Ranjit)2013年

3

这个问题有几个好的答案。这是一个很好的简洁。前两行删除sqlite数据库。然后for:循环删除ManagedObjectContext内存中的所有对象。

NSURL *storeURL = [[(FXYAppDelegate*)[[UIApplication sharedApplication] delegate] applicationDocumentsDirectory] URLByAppendingPathComponent:@"AppName.sqlite"];
[[NSFileManager defaultManager] removeItemAtURL:storeURL error:nil];
for (NSManagedObject *ct in [self.managedObjectContext registeredObjects]) {
    [self.managedObjectContext deleteObject:ct];
}


1
我同意@MichaelDorner。通过相互依赖的相互联系的蜘蛛网,在AppDelegate中添加太多内容可能会影响性能并增加二进制文件的大小,而每个类中突然都需要包含AppDelegate。如果发现这种情况,请创建一个专用于此目的的单独控制器。AppDelegate应该保留用于基本初始化和处理应用程序中的状态更改,仅此而已。
jcpennypincher

2

您还可以找到所有实体名称,并按名称删除它们。它的版本较长,但效果很好,因此您不必使用持久性存储

 - (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”将返回所有实体名称。最后,不要忘记保存。


2

接受的答案是正确的,通过NSFileManager删除URL是正确的,但是正如iOS 5+ edit中所述,持久性存储并不仅由一个文件表示。对于SQLite存储,它是* .sqlite,*。sqlite-shm和* .sqlite-wal ...幸运的是,由于iOS 7+,我们可以使用method

[NSPersistentStoreCoordinator + removeUbiquitousContentAndPersistentStoreAtURL:options:error:]

照顾删除,所以代码应该是这样的:

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];

2
您需要传递选项dict,尤其是商店名称,例如:@ {NSPersistentStoreUbiquitousContentNameKey:@“ MyData”};
tomi44g 2015年

2

这是一个删除您每个表中的每个记录的版本。

斯威夫特4

static func resetDatabase() {
    do {
        try dataStore.persistentStoreCoordinator.managedObjectModel.entities.forEach { (entity) in
            if let name = entity.name {
                let fetch = NSFetchRequest<NSFetchRequestResult>(entityName: name)
                let request = NSBatchDeleteRequest(fetchRequest: fetch)
                try mainContext.execute(request)
            }
        }

        try mainContext.save()
    } catch {
        print("error resenting the database: \(error.localizedDescription)")
    }
}

2

Swift 4/5,iOS 9+

重建整个CoreDataSQLite文件将确保删除所有数据,因此将删除所有实体。只是打电话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()
    }
}

对于使用此功能的任何人,请注意,当那里没有sql文件时,它只会崩溃“第一次”(我在回答中使用了“警卫”)
Fattie

1

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

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

1

我经常使用的另一种方法(基于删除批处理请求)(基于应用程序要求)是重置持久性存储。iOS 10+和Swift的实现看起来像这样(假设您有一个CoreDataManager类):

let persistentContainer: NSPersistentContainer = {
    let container = NSPersistentContainer(name: "<Data-Model-Name>“)
    container.loadPersistentStores(completionHandler: { (storeDescription, err) in
        if let err = err {
            fatalError("loading of store failed: \(err)")
        }
    })
    return container
}()

func resetPersistentStore() {

    if let persistentStore = persistentContainer.persistentStoreCoordinator.persistentStores.last {
        let storeURL = persistentContainer.persistentStoreCoordinator.url(for: persistentStore)

        do {
            try persistentContainer.persistentStoreCoordinator.destroyPersistentStore(at: storeURL, ofType: NSSQLiteStoreType, options: nil)
        } catch {
            print("failed to destroy persistent store:", error.localizedDescription)
        }

        do {
            try persistentContainer.persistentStoreCoordinator.addPersistentStore(ofType: NSSQLiteStoreType, configurationName: nil, at: storeURL, options: nil)
        } catch {
            print("failed to re-add persistent store:", error.localizedDescription)
        }
    }

}

这种方法的一个优点是它更加简单明了,尤其是当您在核心数据中有大量实体的数据记录负载时。在这种情况下,删除批处理请求将占用大量内存。


1

Swift 5.1解决方案

public static func reset() {
    let coordinator = _persistentContainer.persistentStoreCoordinator
    for store in coordinator.persistentStores where store.url != nil {
        try? coordinator.remove(store)
        try? FileManager.default.removeItem(atPath: store.url!.path)
    }
}

0

删除持久性存储文件并设置新的持久性存储协调器?


6
幸运的是,进行清理不会删除持久性存储文件。如果属实,那将是灾难的秘诀。
猎人

0

从您的fileURLPath中删除sqlite,然后进行构建。


我的意思是安装该应用程序时。
Michael Grinich

0

假设您正在使用 MagicalRecord并具有默认的持久性存储:

我不喜欢假设某些文件存在和/或要求输入实体名称或类的所有解决方案。这是从所有实体删除所有数据的一种安全的Swift(2)方法。删除后,它也会重新创建一个新堆栈(实际上,我不确定这部分的必要性)。

当您要删除所有内容但要有一个可用的存储区和Moc来获取新数据时(一旦用户登录...),这是“注销”样式情况的处理方法

extension NSManagedObject {

    class func dropAllData() {

        MagicalRecord.saveWithBlock({ context in

            for name in NSManagedObjectModel.MR_defaultManagedObjectModel().entitiesByName.keys {
                do { try self.deleteAll(name, context: context) }
                catch { print("⚠️ ✏️ Error when deleting \(name): \(error)") }
            }

            }) { done, err in
                MagicalRecord.cleanUp()
                MagicalRecord.setupCoreDataStackWithStoreNamed("myStoreName")
        }
    }

    private class func deleteAll(name: String, context ctx: NSManagedObjectContext) throws {
        let all = NSFetchRequest(entityName: name)
        all.includesPropertyValues = false

        let allObjs = try ctx.executeFetchRequest(all)
        for obj in allObjs {
            obj.MR_deleteEntityInContext(ctx)
        }

    }
}

0

用这个

+(NSArray *)fetchDataFromEntity:(NSString *)entityName context:(NSManagedObjectContext *)context
{
    NSFetchRequest * fetchRequest =[[NSFetchRequest alloc] init];
    NSEntityDescription * CategoriesEntity = [NSEntityDescription entityForName:entityName inManagedObjectContext:context];
    [fetchRequest setEntity:CategoriesEntity];

    NSError * error;
    NSInteger count = [context countForFetchRequest:fetchRequest error:&error];

    if (count && count>0) {

        NSArray * fetchedObjects = [context executeFetchRequest:fetchRequest error:&error];
        if (fetchedObjects && fetchedObjects.count>0) {

            return fetchedObjects;
        }else
            return nil;

    }
    else
        return nil;
}
+ (void)deleteObjectsOfArray:(NSMutableArray*)ary context:(NSManagedObjectContext *)context {
    for (NSManagedObject * obj in ary) {
        [context deleteObject:obj];
    }
    NSError *saveError = nil;
    [context save:&saveError];
}
+ (void)deleteEntity:(NSString *)entityName context:(NSManagedObjectContext *)context {
    NSArray *listArray = [self fetchDataFromEntity:entityName context:context];
    [self deleteObjectsOfArray:[NSMutableArray arrayWithArray:listArray] context:context];
}

0

我采用了Grouchal的代码,并使用并发模式(NSEnumerationConcurrent)进行了加速,与for循环相比,它的速度要快一些(在我的应用中,我为Testers添加了此功能,以便他们可以清除数据并执行测试用例,而不是删除和安装软件)

- (void)resetObjects
{
    [self deleteAllObjectsInEntity:@"Entity1"];
    [self deleteAllObjectsInEntity:@"Entity2"];
    [self deleteAllObjectsInEntity:@"Entity3"];
    [self deleteAllObjectsInEntity:@"Entity4"];
}

-(void) deleteAllObjectsInEntity:(NSString*) entityName
{
    MainDataContext *coreDataContext = [MainDataContext sharedInstance];
    NSManagedObjectContext *currentContext = coreDataContext.managedObjectContext;
    NSFetchRequest *fetchRequest = [[NSFetchRequest alloc] init];
    NSEntityDescription *entity = [NSEntityDescription entityForName:entityName inManagedObjectContext:currentContext];
    [fetchRequest setEntity:entity];

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

    [items enumerateObjectsWithOptions:NSEnumerationConcurrent usingBlock:^(NSManagedObject * obj, NSUInteger idx, BOOL *stop) {
        [currentContext deleteObject:obj];
    }];


    if (![currentContext save:&error]) {
        NSLog(@"Error deleting %@ - error:%@",entityName,error);
    }
}

0

这是我的swift3版本,用于删除所有记录。“用户”是实体名称

@IBAction func btnDelAll_touchupinside(_ sender: Any) {

    let appDelegate = UIApplication.shared.delegate as! AppDelegate
    let managedObjectContext = appDelegate.persistentContainer.viewContext

    let fetchReq = NSFetchRequest<NSFetchRequestResult>(entityName: "Users")
    let req = NSBatchDeleteRequest(fetchRequest: fetchReq)

    do {
        try managedObjectContext.execute(req)

    } catch {
        // Error Handling
    }   
}
By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.