CoreData detect database inconsistency on start up - ios

We have some code to determine if there is no database file currently created. If this is the case, we do some initialization routines to populate the user's database based on some files that may exist on the file system (basically a migration routine).
The routine is basically like this
NSURL * defaultStorePath = [NSPersistentStore MR_defaultLocalStoreUrl];
BOOL initializeDatabase = ![[NSFileManager defaultManager] fileExistsAtPath:[defaultStorePath path]];
[MagicalRecord setupCoreDataStackWithAutoMigratingSqliteStoreAtURL:defaultStorePath];
if(initializeDatabase)
// ... ingest user files ...
So this works well if the .sqlite file is not present. However if the .sqlite-wal or .sqlite-shm files are missing/corrupt, we can't find a way to detect this scenario.
We would like to do a data integrity check or something in this case.

Without MagicalRecord:
NSURL *storeURL = ...
NSError *error;
NSPersistentStore *persistentStore = [_persistentStoreCoordinator addPersistentStoreWithType:NSSQLiteStoreType configuration:nil URL:storeURL options:options error:&error];
if (persistentStore) {
// further initialization
} else {
switch (error.code) {
case NSFileReadCorruptFileError: {
NSLog(#"database corrupted.");
// delete .sqlite, -wal and -shm
// make another attempt to add persistent store
break;
}
case NSPersistentStoreIncompatibleVersionHashError: {
NSLog(#"database model updated.");
// migrate
break;
}
default: {
NSLog(#"unresolved error %#", error.localizedDescription);
abort();
}
}
}

Here is an example, and I hope it will be helpful.
func configurePersistentStore() {
let nc = NSNotificationCenter.defaultCenter()
nc.addObserver(self, selector:#selector(self.dataBaseWillBeRecreated(_:)), name:kMagicalRecordPSCMismatchWillDeleteStore, object:nil)
MagicalRecord.setLoggingLevel(MagicalRecordLoggingLevel.Warn)
// if sqlite database does not match the model you provided, delete store.
// MagicalRecord.setShouldDeleteStoreOnModelMismatch(true)
MagicalRecord.setupCoreDataStackWithStoreNamed(kPersistentStoreName)
if ESGlobal.sharedInstance().firstRun { // User first run your app after installation.
self.fillDefaultDataToSQLiteDB() // fill data
}
}

Related

Migrate persistent store to new location

I need to move my app's database to a new location and stop it from being shared through iCloud automatically.
From my understanding, Apple previously documented that a database should be placed in the Documents directory of an application, but now says that the database should be placed in the Library directory. This is because iOS now shares all data from the Documents directory through iCloud.
My issue is that I need to move my database from the Documents directory to the Library directory. Below is the code I use to do this.
- (NSPersistentStoreCoordinator *)persistentStoreCoordinator {
if (_persistentStoreCoordinator != nil) {
return _persistentStoreCoordinator;
}
_persistentStoreCoordinator = [[NSPersistentStoreCoordinator alloc] initWithManagedObjectModel:[self managedObjectModel]];
// Get the URL of the persistent store
NSURL *oldURL = [[self applicationDocumentsDirectory] URLByAppendingPathComponent:#"App.sqlite"];
bool oldStoreExists = [[NSFileManager defaultManager] fileExistsAtPath:[oldURL path]];
// Get the URL of the new App Group location
NSURL *newURL = [[self applicationLibraryDirectory] URLByAppendingPathComponent:#"App.sqlite"];
bool shouldMoveStore = false;
NSURL *storeURL = nil;
if (!oldStoreExists) {
//There is no store in the old location
storeURL = newURL;
} else {
storeURL = oldURL;
shouldMoveStore = true;
}
NSError *error = nil;
NSDictionary *options = #{ NSMigratePersistentStoresAutomaticallyOption:#YES, NSInferMappingModelAutomaticallyOption:#YES };
if (![_persistentStoreCoordinator addPersistentStoreWithType:NSSQLiteStoreType configuration:nil URL:storeURL options:options error:&error]) {
NSLog(#"Error Moving Store: %ld\nDescription: %#\nReason: %#\nSuggested Fix:%#", (long)error.code, error.localizedDescription, error.localizedFailureReason, error.localizedRecoverySuggestion);
abort();
}
if (shouldMoveStore)
[self movePersistentStoreFrom:oldURL To:newURL];
return _persistentStoreCoordinator;
}
-(void) movePersistentStoreFrom:(NSURL *)oldURL To:(NSURL *)newURL {
// Get the reference to the current persistent store
NSPersistentStore *oldStore = [_persistentStoreCoordinator persistentStoreForURL:oldURL];
// Migrate the persistent store
NSError *error = nil;
[_persistentStoreCoordinator migratePersistentStore:oldStore toURL:newURL options:nil withType:NSSQLiteStoreType error:&error];
if (error) {
NSLog(#"Error Moving Store: %ld\nDescription: %#\nReason: %#\nSuggested Fix:%#", (long)error.code, error.localizedDescription, error.localizedFailureReason, error.localizedRecoverySuggestion);
abort();
}
}
This code seems to work in moving the persistent store, but on the next run of the application the old store is found again and the app attempts to migrate the store a second time. At this point a crash occurs, and I'm assuming it is due to this double migration call. In classic Xcode style, the stack trace is pretty much useless.
Update -
The migratePersistentStore function does not remove ("cut/paste") the old sqlite database, instead it just makes a "copy". It looks like I'll need to remove the old one programmatically.
I switched the code to check if the newStoreExists as opposed to the !oldStoreExists, and the migration does work.
My new issue is that the table rows of the migrated data have become randomized. Any help with this would be appreciated!
Update 2 -
As it turns out, any data migrations like moving the store location or updating the database will randomize your data if you are using Core Data. You need to put an attribute into your table and use a NSSortDescriptor inside of your NSFetchRequest to manually sort the data and keep it ordered.
If you never migrate the data (I previously had not) the core data fetch request always come in the order it was saved.

Magical Record - duplicate records appearing even if DB file is deleted

In my ios app, I am using Magical Record and NSFetchedResultsController. I am trying to implement below functionality:
User navigates to settings screen
He selects - 'Delete Account'
All his data is deleted
He is navigated to re-registration screen
To delete all his data I wrote below code:
- (void)cleanAndResetupDB
{
[MagicalRecord cleanUp];
BOOL isSuccess = YES;
for (NSString *dbStore in [self dbBackups]) {
NSError *error = nil;
NSURL *storeURL = [NSPersistentStore MR_urlForStoreName:dbStore];
if(![[NSFileManager defaultManager] removeItemAtURL:storeURL error:&error]){
NSLog(#"An error has occurred while deleting %#", dbStore);
NSLog(#"Error description: %#", error.description);
isSuccess = NO;
}
}
if (isSuccess) {
[MagicalRecord setupCoreDataStackWithStoreNamed:CRP_DB];
}
}
- (NSArray *)dbBackups
{
NSString *shmFileName = [NSString stringWithFormat:#"%#-shm",CRP_DB];
NSString *walFileName = [NSString stringWithFormat:#"%#-wal",CRP_DB];
return #[CRP_DB,shmFileName,walFileName];
}
When registration is complete user is navigated to contacts screen, where we retrieve related contacts from server and store it in local DB. Since FRC is used to retrieve data from local DB and show it in table view, as soon as data is saved in db it automatically appears in table view.
Problem is-
If I quit the app after removing local db, on relaunch it shows proper records, but if I don't quit the app after removing local db, then it shows duplicate records.
Any clues?
If you are using Core Data and you want to remove your database, you have to actually remove your persistent store. Simply deleting the database files is not enough. Core Data caches objects in memory and if it doesn't know that they should be deleted, they could be re-committed to the database. In particular, you are missing the call to removePersistentStore:error:.
NSPersistentStoreCoordinator *storeCoordinator = ...; // you should already have a persistent store coordinator
NSURL *storeURL = [NSPersistentStore MR_urlForStoreName:dbStore];
[storeCoordinator removePersistentStore:store error:&error];
[[NSFileManager defaultManager] removeItemAtPath:storeURL.path error:&error];

iOS: How can I create a backup copy of my core data base? And how to export/import that copy?

I want to offer the users of my app the possibility to create a backup of the core data database, especially in case he switches to a new device etc.
How would I do that? Especially how can I reimport that file? I mean let's say he makes a backup copy of the database, then changes a ton of stuff and wants to reset to the previous saved backup copy. How would I do that?
Thx!
Take a look at this sample app, it includes functions for making backups, copying backups to and from iCloud, emailing backups and importing backups from email.
http://ossh.com.au/design-and-technology/software-development/sample-library-style-ios-core-data-app-with-icloud-integration/
BTW it's much safer to use migratePersistentStore API to make/import backups if your are doing so to and from ICloud. Also be aware that the sample app assumes you are not using WAL mode which is the default mode for iOS 7. WAL mode uses multiple files which all need to be backed up or copied.
Here is a link to a video demonstrating the sample Apps backup and restore capabilities.
http://ossh.com.au/design-and-technology/software-development/sample-library-style-ios-core-data-app-with-icloud-integration/sample-apps-explanations/backup-files/
Here are the methods used to create copies for backup. Note that it is possible to open the store with multiple persistentStoreCoordinators so no need to close it down while you make a backup. Restoring it does obviously require the existing store to be removed first. Note that there is little difference between the two methods below except that the source store is opened with or without iCloud options.
/*! Creates a backup of the ICloud store
#return Returns YES of file was migrated or NO if not.
*/
- (bool)backupICloudStore {
FLOG(#"backupICloudStore called");
// Lets use the existing PSC
NSPersistentStoreCoordinator *migrationPSC = [[NSPersistentStoreCoordinator alloc] initWithManagedObjectModel:self.managedObjectModel];
// Open the store
id sourceStore = [migrationPSC addPersistentStoreWithType:NSSQLiteStoreType configuration:nil URL:[self icloudStoreURL] options:[self icloudStoreOptions] error:nil];
if (!sourceStore) {
FLOG(#" failed to add old store");
migrationPSC = nil;
return FALSE;
} else {
FLOG(#" Successfully added store to migrate");
NSError *error;
FLOG(#" About to migrate the store...");
id migrationSuccess = [migrationPSC migratePersistentStore:sourceStore toURL:[self backupStoreURL] options:[self localStoreOptions] withType:NSSQLiteStoreType error:&error];
if (migrationSuccess) {
FLOG(#"store successfully backed up");
migrationPSC = nil;
// Now reset the backup preference
[[NSUserDefaults standardUserDefaults] setBool:NO forKey:_makeBackupPreferenceKey];
[[NSUserDefaults standardUserDefaults] synchronize];
return TRUE;
}
else {
FLOG(#"Failed to backup store: %#, %#", error, error.userInfo);
migrationPSC = nil;
return FALSE;
}
}
migrationPSC = nil;
return FALSE;
}
/*! Creates a backup of the Local store
#return Returns YES of file was migrated or NO if not.
*/
- (bool)backupLocalStore {
FLOG(#"backupLocalStore called");
// Lets use the existing PSC
NSPersistentStoreCoordinator *migrationPSC = [[NSPersistentStoreCoordinator alloc] initWithManagedObjectModel:self.managedObjectModel];
// Open the store
id sourceStore = [migrationPSC addPersistentStoreWithType:NSSQLiteStoreType configuration:nil URL:[self localStoreURL] options:[self localStoreOptions] error:nil];
if (!sourceStore) {
FLOG(#" failed to add old store");
migrationPSC = nil;
return FALSE;
} else {
FLOG(#" Successfully added store to migrate");
NSError *error;
FLOG(#" About to migrate the store...");
id migrationSuccess = [migrationPSC migratePersistentStore:sourceStore toURL:[self backupStoreURL] options:[self localStoreOptions] withType:NSSQLiteStoreType error:&error];
if (migrationSuccess) {
FLOG(#"store successfully backed up");
migrationPSC = nil;
// Now reset the backup preference
[[NSUserDefaults standardUserDefaults] setBool:NO forKey:_makeBackupPreferenceKey];
[[NSUserDefaults standardUserDefaults] synchronize];
return TRUE;
}
else {
FLOG(#"Failed to backup store: %#, %#", error, error.userInfo);
migrationPSC = nil;
return FALSE;
}
}
migrationPSC = nil;
return FALSE;
}
/** Sets the selected file as the current store.
Creates a backup of the current store first.
#param fileURL The URL for the file to use.
*/
- (BOOL)restoreFile:(NSURL *)fileURL {
FLOG(#" called");
// Check if we are using iCloud
if (_isCloudEnabled) {
FLOG(#" using iCloud store so OK to restore");
NSURL *currentURL = [self storeURL];
FLOG(#" currentURL is %#", currentURL);
FLOG(#" URL to use is %#", fileURL);
[self saveContext];
[self backupCurrentStoreWithNoCheck];
// Close the current store and delete it
_persistentStoreCoordinator = nil;
_managedObjectContext = nil;
[self removeICloudStore];
[self moveStoreFileToICloud:fileURL delete:NO backup:NO];
} else {
FLOG(#" using local store so OK to restore");
NSURL *currentURL = [self storeURL];
FLOG(#" currentURL is %#", currentURL);
FLOG(#" URL to use is %#", fileURL);
[self saveContext];
[self backupCurrentStoreWithNoCheck];
// Close the current store and delete it
_persistentStoreCoordinator = nil;
_managedObjectContext = nil;
NSError *error = nil;
NSFileManager *fm = [[NSFileManager alloc] init];
// Delete the current store file
if ([fm fileExistsAtPath:[currentURL path]]) {
FLOG(#" target file exists");
if (![fm removeItemAtURL:currentURL error:&error]) {
FLOG(#" error unable to remove current store file");
NSLog(#"Error removing item Error: %#, %#", error, error.userInfo);
return FALSE;
} else {
FLOG(#" current store file removed");
}
}
//
//simply copy the file over
BOOL copySuccess = [fm copyItemAtPath:[fileURL path]
toPath:[currentURL path]
error:&error];
if (copySuccess) {
FLOG(#" replaced current store file successfully");
//[self postFileUpdateNotification];
} else {
FLOG(#"Error copying items Error: %#, %#", error, error.userInfo);
return FALSE;
}
}
// Now open the store again
[self openPersistentStore];
return TRUE;
}
Whatever the persistent store is that you use (binary, SQLite, etc.); it is just a file on the filesystem. You can make a copy of it whenever you want.
If you are using SQLite in iOS 7, be sure to make a copy of the other files associated with it as they are the journal files that go with it. If you are using binary then there will be only a single file.
If you just copy the file there is no import step, you just copy it back to restore it.
There are more advanced designs such as exporting the entire database to something that is portable, such as JSON but that is a different subject.
Update
Well I've used the standard Xcode core data template, so according to the code I've just checked I'm using SQLite. So how do I find all related files? Or could you show me with some example code how to copy and insert back the files needed?
You use NSFileManager to copy the files. You can look at the documents directory in your iOS simulator application to see the names of all the files. Or you could use NSFileManager to scan the documents directory, find everything that starts with the same file name (MyData.* for example) and copy that into a back up directory.
As for sample code, no; it is only a couple of lines of code once you look at the documentation for NSFileManager.
I created the following method with the help of Apple sample code. This will take a backup of core data files and place it to the path that you want.
Swift 5
/// Backing up store type to a new and unique location
/// The method is illustrated in the following code fragment, which shows how you can use migratePersistentStore to take a back up of a store and save it from one location to another.
/// If the old store type is XML, the example also converts the store to SQLite.
/// - Parameters:
/// - path: Where you want the backup to be done, please create a new unique directory with timestamp or the guid
/// - completion: Passes error in case of error or pass nil in case of success
class func backUpCoreDataFiles(path : URL, completion : #escaping (_ error : String?) -> ())
{
// Every time new container is a must as migratePersistentStore method will loose the reference to the container on migration
let container = NSPersistentContainer(name : "<YourDataModelName>")
container.loadPersistentStores
{ (storeDescription, error) in
if let error = error
{
fatalError("Failed to load store: \(error)")
}
}
let coordinator = container.persistentStoreCoordinator
let store = coordinator.persistentStores[0]
do
{
try coordinator.migratePersistentStore(store, to : path, options : nil, withType : NSSQLiteStoreType)
completion(nil)
}
catch
{
completion("\(Errors.coredataBackupError)\(error.localizedDescription)")
}
}

CoreData with multiple databases

I'm building an app that is going to rely on 3 separate .sqlite databases. What methods in my App Delegate am I going to have to edit to allow for this? Right now, my managedObjectContext and managedObjectModel haven't been touched from how the template created them. My persistantStoreCoordinator looks like this:
- (NSPersistentStoreCoordinator *)persistentStoreCoordinator
{
if (_persistentStoreCoordinator != nil)
{
return _persistentStoreCoordinator;
}
NSURL *storeURLConfigA = [[self applicationDocumentsDirectory] URLByAppendingPathComponent:#"dbA.sqlite"];
NSURL *storeURLConfigB = [[self applicationDocumentsDirectory] URLByAppendingPathComponent:#"dbB.sqlite"];
NSURL *storeURLConfigC = [[self applicationDocumentsDirectory] URLByAppendingPathComponent:#"dbC.sqlite"];
// // Pre-load .sqlite db in Project Navigator into app on first run after deleting app
if (![[NSFileManager defaultManager] fileExistsAtPath:[storeURLConfigA path]])
// dbA
{
NSURL *preloadURL = [NSURL fileURLWithPath:[[NSBundle mainBundle] pathForResource:#"dbA" ofType:#"sqlite"]];
NSError* err = nil;
if (![[NSFileManager defaultManager] copyItemAtURL:preloadURL toURL:storeURLConfigA error:&err])
{
NSLog(#"Error preloading database A - %#",error.description);
}
}
if (![[NSFileManager defaultManager] fileExistsAtPath:[storeURLConfigB path]])
// dbB
{
NSURL *preloadURL = [NSURL fileURLWithPath:[[NSBundle mainBundle] pathForResource:#"dbB" ofType:#"sqlite"]];
NSError* err = nil;
if (![[NSFileManager defaultManager] copyItemAtURL:preloadURL toURL:storeURLConfigB error:&err])
{
NSLog(#"Error preloading database B - %#",error.description);
}
}
if (![[NSFileManager defaultManager] fileExistsAtPath:[storeURLConfigC path]])
// dbC
{
NSURL *preloadURL = [NSURL fileURLWithPath:[[NSBundle mainBundle] pathForResource:#"dbC" ofType:#"sqlite"]];
NSError* err = nil;
if (![[NSFileManager defaultManager] copyItemAtURL:preloadURL toURL:storeURLConfigC error:&err])
{
NSLog(#"Error preloading database C - %#",error.description);
}
}
// // Put the Configs into the PersistantStoreCoordinator and tie them to their database file
NSError *error = nil;
_persistentStoreCoordinator = [[NSPersistentStoreCoordinator alloc] initWithManagedObjectModel:[self managedObjectModel]];
NSDictionary *options = #{NSSQLitePragmasOption : #{#"journal_mode": #"DELETE"}};
if (![_persistentStoreCoordinator addPersistentStoreWithType:NSSQLiteStoreType configuration:#"Config_A" URL:storeURLConfigA options:options error:&error])
{
NSLog(#"Error setting up dbA - %#",error.description);
abort();
}
if (![_persistentStoreCoordinator addPersistentStoreWithType:NSSQLiteStoreType configuration:#"Config_B" URL:storeURLConfigB options:options error:&error])
{
NSLog(#"Error setting up dbB - %#",error.description);
abort();
}
if (![_persistentStoreCoordinator addPersistentStoreWithType:NSSQLiteStoreType configuration:#"Config_C" URL:storeURLConfigC options:options error:&error])
{
NSLog(#"Error setting up dbC - %#",error.description);
abort();
}
return _persistentStoreCoordinator;
}
Then, I have a single .xcdatamodelID in my mainBundle that has all of my tables/Entities in it, for all three databases. I used XCode's CoreData editor interface to add Configurations Config_A, Config_B, and Config_C, in addition to the Default Configuration. I've moved the Entities into the Configurations for the databases I want them to be in (each Entity should only be in one database).
I run the app and everything runs fine, and I can read and write data without any problem. The problem comes when I view the tables (through the terminal or Firefox's SQLite Manager, for example). All 3 of the databases contain all of the tables, but the tables only have data in the database they are supposed to exist in (there are 0 rows in that table in the other two databases).
Why are all of the tables in each database? How can I get each database to only include the couple tables I want them to have?
You have added all 3 of your databases (NSPersistentStores) to the same NSPersistentStoreCoordinator. Therefore, when you perform a save on a Managed Object Context, the store coordinator distributes those changes to all of its stores. Instead, create a persistent store coordinator for each database, perhaps keeping them in an NSDictionary, with a key #"A" for the A database persistent store coordinator, key #"B" for the B database coordinator, etc. Then when you create a new managed object context, you will have to determine which database (NSPersistentStoreCoordinator) it belongs to. This will allow you to keep your tables/changes separated and prevent all data going into all 3 databases.
I started with what Patrick Goley had in his answer, but I still couldn't get the behavior I was looking for. After reading what he had, I got the idea to just go and break my three databases into totally separate pieces everywhere I could think of doing so, and that seems to be working. If someone needs me to post my whole app delegate I will, but the gist of it is:
I have properties for 3 NSManagedObjectContexts, 3 NSManagedObjectModels, and 3 NSPersistantStoreCoordinators.
I copied the factory methods to create each (which were originally written when I created my app from a template) and hardcoded each to use the appropriate contexts/models/store coordinators.
I have 3 NSSets that holds the table names for it's respective database, and when I want to read from (or save to) a table, I pass the name of that table, and use the NSSets to get the appropriate context/model/store coordinator.
After spending a lot of time reading all the Apple docs and other threads I could find, I feel like it wasn't supposed to be this difficult to support separate databases, but this was the only thing that's actually doing what I want so far. I don't know what I was missing before, but this is working, so it will do for now. If I get more free time in the future I might look into it more and try to figure out the right way, and if I find it I'll update.

How do I delete all objects from my persistent store in Core Data?

I have Core Data working in my app. So, I fetch an XML file, parse the data into model objects and insert them into core data. They are saved in the persistent store and I can access them when I relaunch the app. However, I want to be able to refresh the data in the persistent store at will, so I need to first remove existing objects from the store. Is there a straight-forward method for this?
Thanks
I found this solution:
[managedObjectContext lock];
[managedObjectContext reset];//to drop pending changes
if ([persistentStoreCoordinator removePersistentStore:persistentStore error:&error])
{
NSURL* storeURL = [NSURL fileURLWithPath:[self pathForPersistentStore]];
[[NSFileManager defaultManager] removeFileAtPath:[storeURL path] handler:nil];
[self addPersistentStore];//recreates the persistent store
}
[managedObjectContext unlock];
Here's what I have done to clean my Core Data entirely. It works perfectly. This is if you only have one persistent store which is probably the case if you didn't add one more manually. If your managedObjectContext has the same name as here you can simply copy/past it will work.
NSError * error;
// retrieve the store URL
NSURL * storeURL = [[managedObjectContext persistentStoreCoordinator] URLForPersistentStore:[[[managedObjectContext persistentStoreCoordinator] persistentStores] lastObject]];
// lock the current context
[managedObjectContext lock];
[managedObjectContext reset];//to drop pending changes
//delete the store from the current managedObjectContext
if ([[managedObjectContext persistentStoreCoordinator] removePersistentStore:[[[managedObjectContext persistentStoreCoordinator] persistentStores] lastObject] error:&error])
{
// remove the file containing the data
[[NSFileManager defaultManager] removeItemAtURL:storeURL error:&error];
//recreate the store like in the appDelegate method
[[managedObjectContext persistentStoreCoordinator] addPersistentStoreWithType:NSSQLiteStoreType configuration:nil URL:storeURL options:nil error:&error];//recreates the persistent store
}
[managedObjectContext unlock];
//that's it !
swift version of #Nicolas Manzini answer:
if let psc = self.managedObjectContext?.persistentStoreCoordinator{
if let store = psc.persistentStores.last as? NSPersistentStore{
let storeUrl = psc.URLForPersistentStore(store)
self.managedObjectContext?.performBlockAndWait(){
self.managedObjectContext?.reset()
var error:NSError?
if psc.removePersistentStore(store, error: &error){
NSFileManager.defaultManager().removeItemAtURL(storeUrl, error: &error)
psc.addPersistentStoreWithType(NSSQLiteStoreType, configuration: nil, URL: storeUrl, options: nil, error: &error)
}
}
}
}
Based on #Nicolas Manzini answer I have wrote a Swift 2.1 version with little improvements. I have added an extension to NSManagedObjectContext. Full code below:
import Foundation
import CoreData
extension NSManagedObjectContext
{
func deleteAllData()
{
guard let persistentStore = persistentStoreCoordinator?.persistentStores.last else {
return
}
guard let url = persistentStoreCoordinator?.URLForPersistentStore(persistentStore) else {
return
}
performBlockAndWait { () -> Void in
self.reset()
do
{
try self.persistentStoreCoordinator?.removePersistentStore(persistentStore)
try NSFileManager.defaultManager().removeItemAtURL(url)
try self.persistentStoreCoordinator?.addPersistentStoreWithType(NSSQLiteStoreType, configuration: nil, URL: url, options: nil)
}
catch { /*dealing with errors up to the usage*/ }
}
}
}
There is a function
According to WWDC 242, you can use it for clearing a database.
Also there is a func replacePersistentStore which is replacing the current database with a selected one.
You could loop through all objects and delete them by doing this:
[managedObjectContext deleteObject:someObject];
If you want to remove all objects it is probably fastest to delete the store and then recreate the CoreData stack.
Trash your data file and remake it.
import Foundation
import CoreData
extension NSManagedObjectContext
{
func deleteAllData() {
guard let persistentStore = persistentStoreCoordinator?.persistentStores.last else {
return
}
guard let url = persistentStoreCoordinator?.url(for: persistentStore) else {
return
}
performAndWait { () -> Void in
self.reset()
do
{
try self.persistentStoreCoordinator?.remove(persistentStore)
try FileManager.default.removeItem(at: url)
try self.persistentStoreCoordinator?.addPersistentStore(ofType: NSSQLiteStoreType, configurationName: nil, at: url, options: nil)
}
catch { /*dealing with errors up to the usage*/ }
}
}
}
Thanks #Julian Krol - updated answer for Swift 5.1
The fastest way to ditch everything is to send your managed object context the reset message.

Resources