Delete/Reset all entries in Core Data?
Asked Answered
M

33

248

Do you know of any way to delete all of the entries stored in Core Data? My schema should stay the same; I just want to reset it to blank.


Edit

I'm looking to do this programmatically so that a user can essentially hit a reset button.

Marlborough answered 3/7, 2009 at 4:55 Comment(2)
Many of the answers below are dated. Use NSBatchDeleteRequest. https://mcmap.net/q/115998/-delete-reset-all-entries-in-core-dataAbrahamabrahams
Possible duplicate of Core Data: Quickest way to delete all instances of an entityOsmose
C
202

You can still delete the file programmatically, using the NSFileManager:removeItemAtPath:: method.

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

Then, just add the persistent store back to ensure it is recreated properly.

The programmatic way for iterating through each entity is both slower and prone to error. The use for doing it that way is if you want to delete some entities and not others. However you still need to make sure you retain referential integrity or you won't be able to persist your changes.

Just removing the store and recreating it is both fast and safe, and can certainly be done programatically at runtime.

Update for iOS5+

With the introduction of external binary storage (allowsExternalBinaryDataStorage or Store in External Record File) in iOS 5 and OS X 10.7, simply deleting files pointed by storeURLs is not enough. You'll leave the external record files behind. Since the naming scheme of these external record files is not public, I don't have a universal solution yet. – an0 May 8 '12 at 23:00

Cheka answered 3/8, 2009 at 12:42 Comment(15)
This is probably the best solution for reliability. If I wanted to delete some but not all data, I would use this: #1078310Marlborough
how would you find the URL of the persistent store?Ewing
I know how to properly retrieve the storeCoordinator. However I dont know how to get the persistentStore. So could you please give a proper example instead of just: NSPersistentStore * store = ...;Souvaine
[[NSFileManager defaultManager] removeItemAtURL:storeURL error:&error] is better.Always
@Pascal If you can get the store coordinator then yo have access to all its persistent stores through the persistentStores property.Rapture
@MihaiDamian so ... the correct answer should start with the line: "for( NSPersistentStore* store in [self.persistentStoreCoordinator persistentStores] )" ?Rotarian
Tony, all variables in ObjC are initialized to nil automatically, as far as I know.Substantiate
I think this approach has a problem. What about when you have some NSData attributtes and you check (in iOS5) the option "Allows External Persistence". Perhaps in this case, some pictures are saved as a files and you don't delete them when deleting the SQL file.Substantiate
With the introduction of external binary storage(allowsExternalBinaryDataStorage or Store in External Record File) in iOS 5 and OS X 10.7, simply deleting files pointed by storeURLs is not enough. You'll leave the external record files behind. Since the naming scheme of these external record files is not public, I don't have a universal solution yet.Always
@MihaiDamian [self.persistentStoreCoordinator.persistentStores lastObject]Mallis
If you're lucky enough to use RestKit, you can do [RKManagedObjectStore deleteStoreInApplicationDataDirectoryWithFilename:databaseName];Pam
This code passes the same error through two different method calls one after another: is that valid?Guidebook
Valid, yes, good idea... less so. Actually, to be explicit, he's passing a REFERENCE to two different calls, which is fine. It's the not checking to see if he had an error that's an issue; with this code, he might as well pass in the equally-valid 'nil'.Mauldon
Example code including how to recreate a new empty store here: stackoverflow.com/a/8467628Marlanamarlane
is there any way in which I can reset the data in all the entities except one from the store url?? for eg: lets say we have 3 entities A,B and C. I want to reset the data in A and B but not C. C should be remained the same. Anyway in which this can be implemented?Desiderative
S
142

You can delete the SQLite file - but I choose to do it by purging the tables individually with a functions:

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

}

The reason I chose to do it table by table is that it makes me confirm as I am doing the programming that deleting the contents of the table is sensible and there is not data that I would rather keep.

Doing it this will is much slower than just deleting the file and I will change to a file delete if I this method takes too long.

Stannic answered 3/7, 2009 at 8:12 Comment(8)
Great solution. Thanks. What's DLog()?Marlborough
Ah yes - sorry that is a special function I use that only does an NSLog when the build is a DEBUG build - just replace with NSLog.Stannic
You can see an implementation of DLog here: cimgf.com/2009/01/24/dropping-nslog-in-release-buildsEdd
is there any way to delete data of a particular attribute?Mozellamozelle
This works nicely for me. But to make it go faster, is there a way to delete all the objects of a certain entity with one command? Like in SQL you could do something like, DROP TABLE entity_name. I don't want to delete the whole SQL file because I only want to delete all objects of a specific entity, not other entities.Exchequer
I found this code in the persistentStoreCoordinator accessor method that comes by default in core data templates:NSURL *storeURL = [[self applicationDocumentsDirectory] URLByAppendingPathComponent:@"MyApp.sqlite"];Mazza
Use NSDictionary *allEntities = _managedObjectModel.entitiesByName; to get all entities in your model and then you can iterate over the keys in this NSDictionary to purge all entities in the store.Motherwell
Thank you, this really helped me as the data seemed to be so stubborn and won't delete when I tried the normal coredata delete. ThanksPoland
A
72

Updated Solution for iOS 10+

Use NSBatchDeleteRequest to delete all objects in the entity without having to load them into memory or iterate through them.

// 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 {
    print(error.localizedDescription)
}

This code has been updated for iOS 10 and Swift 3. If you need to support iOS 9, see this question.

Sources:

Abrahamabrahams answered 12/8, 2015 at 9:34 Comment(2)
I would place that entire block inside a moc.performBlockAndWait({ () -> Void in ... }).Sidras
Make sure you see Why entries are not deleted until app is restarted or I execute my NSBatchDeleteRequest twice? Long story the above code is NOT enough if the entities are loaded into the memoryAllethrin
E
40

I've written a clearStores method that goes through every store and delete it both from the coordinator and the filesystem (error handling left aside):

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;

This method is inside a coreDataHelper class that takes care of (among other things) creating the persistentStore when it's nil.

Egomania answered 10/6, 2010 at 5:30 Comment(1)
"no known class method for selector 'persistentStores'"Probable
O
27

I remove all data from core data on a button Event in a HomeViewController class: This article helped me so much I figured I'd contribute.

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

}

Note that in order to call self.persistentStoreCoordinator I declared a property in the Home View Controller. (Don't worry about the managedObjectContext that I use for saving and loading.)

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

Then in the AppDelegate ApplicationDidFinishLaunching right below creating a HomeViewController I have :

homeViewController = [[HomeViewController alloc] initWithNibName:@"HomeViewController" bundle:nil];
homeViewController.managedObjectContext = self.managedObjectContext;
homeViewController.persistentStoreCoordinator = self.persistentStoreCoordinator;
Oliver answered 5/12, 2011 at 19:19 Comment(5)
@ayteat, did this work for you?. for me its not working, please have a look at this #14647095Mineralogist
THIS IS THE ANSWER except use "AppDelegate *ad = [[UIApplication sharedApplication] delegate];" and replace self with ad. and dont copy last two bits of codeTankage
Why are you not calling reset on managedObjectContext? What if you have some strong reference to managedObject?Sydney
@ParagBafna You are correct, the code sample above assumes that there are no strong references to managed objects. If you have some, you should look at calling 'reset' on the managedObjectContext and de-reference any managed objects you have.Oliver
Hey,Thanks. Also,is there any way to do this on app upgrade? To be precise,my requirement is when I am rolling our next version of app,that time when the user update their app from appStore, the core data n sqlite files should be deleted and reinitialized to blank. I figured out way to detect app first launch event using a Bool value in NSUserDefaults and checking this value in app delegate's didfinishLaunchingWithOptions, but did not understand how to clear all these things. Since there is no button and app delegate is not detecting my "persistentStore" to clear it as you did above. any Help?Leguminous
H
21

iOS9+, Swift 2

Delete all objects in all entities

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)
        }
    }
}
Hacking answered 20/5, 2016 at 13:55 Comment(1)
Make sure you see Why entries are not deleted until app is restarted or I execute my NSBatchDeleteRequest twice? Long story the above code is NOT enough if the entities are loaded into the memoryAllethrin
P
19

MagicalRecord makes this very easy.

[MyCoreDataObject MR_truncateAll];
Prerecord answered 5/4, 2011 at 14:50 Comment(5)
this is cool, but off topic since I specified a CoreData solutionMarlborough
Active Record Fetching is a core data solution.Mose
But an answer like this goes beyond the scope of the question. There is no reason to assume he wants to use an addt'l framework to do this.Penta
I'd argue that this doesn't answer the question. This is a good way to remove entries from one entity, not all entities...! How do you enumerate through all entities in the model and send MR_truncateAll on them?Ency
View the source for MR_truncateAll -- it fetches all the objects but not their properties (as we intend to discard the NSMOs), then it iterates over the objects for the specified entity and deletes them. github.com/magicalpanda/MagicalRecord/blob/master/MagicalRecord/…Calysta
H
14

[Late answer in response to a bounty asking for newer responses]

Looking over earlier answers,

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

You'd do something like this when setting up your persistent store:

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

Then when you wanted to remove the store,

[[NSFileManager defaultManager] removeItemAtURL:storeDirectoryURL error:nil];

That recursively removes both the custom sub-directory and all of the Core Data files in it.

This only works if you don't already have your persistent store in the same folder as other, important data. Like the documents directory, which probably has other useful stuff in it. If that's your situation, you could get the same effect by looking for files that you do want to keep and removing everything else. Something like:

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

This approach may be error prone. You've got to be absolutely sure that you know every file you want to keep, because otherwise you might remove important data. On the other hand, you can remove the external binary files without actually knowing the file/directory name used to store them.

Haught answered 5/12, 2013 at 21:12 Comment(1)
if you're afraid of the wal file, just disable itTab
V
11

Here is combined solution for purging Core Data.

- (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]);
        }
    }  
}
Vick answered 10/10, 2013 at 9:6 Comment(0)
M
10

If you want to delete all objects and do not want to delete the backing files, you can use following methods:

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

Beware that it may be very slow (depends on how many objects are in your object graph).

Mayhem answered 22/2, 2013 at 17:48 Comment(1)
how to remove the older data (say three tables, from one table I want to clear data)when app updatesTichonn
C
6

If you want to go the delete all objects route (which is much simpler than tearing down the Core Data stack, but less performant), than this is a better implementation:

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

This implementation leverages NSOperation to perform the deletion off of the main thread and notify on completion. You may want to emit a notification or something within the completion block to bubble the status back to the main thread.

Chromatophore answered 20/12, 2012 at 22:51 Comment(1)
Note that your NSManagedObjectContext must be initialized like NSManagedObjectContext *context = [[NSManagedObjectContext alloc] initWithConcurrencyType:NSPrivateQueueConcurrencyType]; in order to use this method or else you get the error: Can only use -performBlock: on an NSManagedObjectContext that was created with a queue. Romeoromeon
H
6

iOS 10 + Swift 3 solution:

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

Iterates through all of the core data entities and clears them

Hughey answered 26/9, 2016 at 6:18 Comment(0)
B
6

Swift 4/5, iOS 9+

Rebuilding the whole CoreData SQLite file will make sure all data is erased, therefore all entities are deleted. Just call 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()
    }
}
Breazeale answered 12/10, 2019 at 10:42 Comment(1)
for anyone using this, do note that it will just crash the "first time" when there's no sql file there (I just used a "guard" in my answer)Copyist
C
4

Thanks for the post. I followed it and it worked for me. But I had another issue that was not mentioned in any of the replies. So I am not sure if it was just me.

Anyway, thought I would post here the problem and my way that solved it.

I had a few records in the database, I wanted to purge everything clean before write new data to the db, so I did everything including

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

and then used managedObjectContext to access the database (supposed to be empty by now), somehow the data was still there. After a while of troubleshooting, I found that I need to reset managedObjectContext, managedObject, managedObjectModel and persistentStoreCoordinator, before I use managedObjectContext to access the dabase. Now I have a clean database to write to.

Croaker answered 12/12, 2011 at 21:50 Comment(1)
So resetting managedObjectContext, managedObject, managedObjectModel and persistentStoreCoordinator puts the file containing the database back after it has been deleted?Circumnavigate
S
4

Here is a somewhat simplified version with less calls to AppDelegate self and the last bit of code that was left out of the top rated answer. Also I was getting an error "Object's persistent store is not reachable from this NSManagedObjectContext's coordinator" so just needed to add that back.

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];
}
Sayer answered 8/11, 2012 at 17:13 Comment(0)
B
4

swift solution:

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)
    }
Bhili answered 6/9, 2014 at 8:18 Comment(1)
For swift 2 let modelURL = NSBundle.mainBundle().URLForResource("some string", withExtension: "momd")!Cormier
D
4

Here's a version that deletes every record in every table you have.

Swift 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)")
    }
}
Damascene answered 7/3, 2018 at 3:27 Comment(0)
T
3

As a quick reference to save searching elsewhere - recreating the persistent store after deleting it can be done with:

if (![persistentStoreCoordinator addPersistentStoreWithType:NSSQLiteStoreType configuration:nil URL:storeURL options:nil error:&error]) {
// do something with the error
}
Tweedsmuir answered 29/9, 2011 at 9:43 Comment(1)
I tried your code, but xcode throws an exception on this line,So what you have to say about this.Mineralogist
D
3

Several good answers to this question. Here's a nice concise one. The first two lines delete the sqlite database. Then the for: loop deletes any objects in the managedObjectContext memory.

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];
}
Deen answered 5/8, 2012 at 0:19 Comment(2)
Don't abuse the delegation for this purpose: hollance.com/2012/02/dont-abuse-the-app-delegateRepublicanism
I agree with @MichaelDorner. Adding to much into AppDelegate can impact performance and bloat the size of your binary with an interconnected spiderweb of dependencies where AppDelegate suddenly needs to be included in every class. If you find this cropping up, create a seperate controller specific to this purpose. AppDelegate should remain for basic initialization and handling state changes in the application, not much more.Vharat
C
2

you can also find all the entity names, and delete them by name. Its a longer version but works well, that way you dont have to work with persistence store

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

for "Any_Entity_Name" just give any one of your entity's name, we only need to figure out the entity description your entities are within. ValueForKey@"name" will return all the entity names. Finally, dont forget to save.

Combes answered 7/12, 2012 at 6:40 Comment(0)
P
2

The accepted answer is correct with removing URL by NSFileManager is correct, but as stated in iOS 5+ edit, the persistent store is not represented only by one file. For SQLite store it's *.sqlite, *.sqlite-shm and *.sqlite-wal ... fortunately since iOS 7+ we can use method

[NSPersistentStoreCoordinator +removeUbiquitousContentAndPersistentStoreAtURL:options:error:]

to take care of removal, so the code should be something like this:

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];
Plauen answered 28/1, 2015 at 13:44 Comment(1)
You need to pass the options dict, in particular the store name, e.g.: @{NSPersistentStoreUbiquitousContentNameKey: @"MyData"};Solothurn
R
2

One other method (apart from a delete batch request) I often use (based on app requirement) is to reset the persistent store. The implementation looks like this for iOS 10+ and Swift (assuming you have a CoreDataManager class):

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

}

One advantage of this method is that it’s more straightforward especially when you have loads of data record for numerous entities in your core data. In which case a delete batch request would be memory intensive.

Reamonn answered 2/7, 2019 at 4:26 Comment(0)
G
2

Swift 5.1 Solution

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)
    }
}
Gewgaw answered 12/10, 2019 at 6:16 Comment(0)
E
1

Works with all versions. Pass entity name and iterate through to delete all the entries and save the context.

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)")
    }
}
Exsanguinate answered 2/3, 2017 at 12:19 Comment(0)
C
1

There seems to be two approaches:

Say you have a typical singleton for your core data stack.

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

then ...

    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. scorch the sql file

Courtesy the excellent @J.Doe answer. You completely destroy the sql file.

You must to do this

  • before loading core data, ie, after creating the container, but
  • before actually loading the stores.)

(Notice the example line of code "//deleteSql()" is just before initialization.)

2. delete everything one by one within core data

Courtesy the excellent @Politta answer. You could do this at any time once core data is up and running.

(Notice the example line of code "//deleteAll()" is after initialization.)

Approach one is probably more useful during development. Approach two is probably more useful in production (in the relatively unusual case that for some reason you need to wipe everything).

Copyist answered 3/2, 2020 at 13:46 Comment(0)
W
0

Delete the persistent store file and setup a new persistent store coordinator?

Walrath answered 3/7, 2009 at 5:9 Comment(1)
Doing a clean will not remove the persistent store files, thankfully. That would be a recipe for disaster if true.Walrath
O
0

Delete sqlite from your fileURLPath and then build.

Ogg answered 3/7, 2009 at 11:56 Comment(1)
I meant when the app is installed.Marlborough
B
0

Assuming you are using MagicalRecord and have a default persistence store:

I don't like all the solutions that assume certain files to exist and/or demand entering the entities names or classes. This is a Swift(2), safe way to delete all the data from all the entities. After deleting it will recreate a fresh stack too (I am actually not sure as to how neccessery this part is).

It's godo for "logout" style situations when you want to delete everything but have a working store and moc to get new data in (once the user logs in...)

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

    }
}
Bijugate answered 8/11, 2015 at 16:20 Comment(0)
R
0

Use this

+(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];
}
Roue answered 16/2, 2016 at 6:46 Comment(0)
P
0

I took Grouchal's code and to speed it up I used enumeration with concurrent mode (NSEnumerationConcurrent), it got a bit faster compared to for loop (in my app I added this feature for Testers so that they can clear data and do testcases rather than delete and install app)

- (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);
    }
}
Peroxidase answered 4/3, 2016 at 13:19 Comment(0)
B
0

here my swift3 version for delete all records. 'Users' is entity name

@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
    }   
}
Beautician answered 25/2, 2017 at 14:30 Comment(0)
P
0

iOS 10 and Swift 3

Assuming that your entity name is "Photo", and that you create a CoreDataStack class...

 func clearData() {
        do {            
            let context = CoreDataStack.sharedInstance.persistentContainer.viewContext
            let fetchRequest = NSFetchRequest<NSFetchRequestResult>(entityName: "Photo")
            do {
                let objects  = try context.fetch(fetchRequest) as? [NSManagedObject]
                _ = objects.map{$0.map{context.delete($0)}}
                CoreDataStack.sharedInstance.saveContext()
            } catch let error {
                print("ERROR DELETING : \(error)")
            }
        }
    }

Here is a good tutorial of how to use CoreData and how to use this method. https://medium.com/compileswift/parsing-json-response-and-save-it-in-coredata-step-by-step-fb58fc6ce16f#.1tu6kt8qb

Pender answered 15/3, 2017 at 5:16 Comment(0)
V
-8

you're all making this seem complicated. You can just send your NSManagedObjectContext the reset method

Vervain answered 12/3, 2012 at 1:29 Comment(1)
That only resets unsaved changes instead of removing all objects.Consonantal

© 2022 - 2024 — McMap. All rights reserved.