Core Data: Quickest way to delete all instances of an entity
Asked Answered
I

29

443

I'm using Core Data to locally persist results from a Web Services call. The web service returns the full object model for, let's say, "Cars" - could be about 2000 of them (and I can't make the Web Service return anything less than 1 or ALL cars.

The next time I open my application, I want to refresh the Core Data persisted copy by calling the Web Service for all Cars again, however to prevent duplicates I would need to purge all data in the local cache first.

Is there a quicker way to purge ALL instances of a specific entity in the managed object context (e.g. all entities of type "CAR"), or do I need to query them call, then iterate through the results to delete each, then save?

Ideally I could just say delete all where entity is Blah.

Immitigable answered 5/9, 2009 at 15:29 Comment(1)
You could use an in memory databasePersonalize
P
795

iOS 9 and later:

iOS 9 added a new class called NSBatchDeleteRequest that allows you to easily delete objects matching a predicate without having to load them all in to memory. Here's how you'd use it:

Swift 5

let fetchRequest: NSFetchRequest<NSFetchRequestResult> = NSFetchRequest(entityName: "Car")
let deleteRequest = NSBatchDeleteRequest(fetchRequest: fetchRequest)

do {
    try myPersistentStoreCoordinator.execute(deleteRequest, with: myContext)
} catch let error as NSError {
    // TODO: handle the error
}

Objective-C

NSFetchRequest *request = [[NSFetchRequest alloc] initWithEntityName:@"Car"];
NSBatchDeleteRequest *delete = [[NSBatchDeleteRequest alloc] initWithFetchRequest:request];

NSError *deleteError = nil;
[myPersistentStoreCoordinator executeRequest:delete withContext:myContext error:&deleteError];

More information about batch deletions can be found in the "What's New in Core Data" session from WWDC 2015 (starting at ~14:10).

iOS 8 and earlier:

Fetch 'em all and delete 'em all:

NSFetchRequest *allCars = [[NSFetchRequest alloc] init];
[allCars setEntity:[NSEntityDescription entityForName:@"Car" inManagedObjectContext:myContext]];
[allCars setIncludesPropertyValues:NO]; //only fetch the managedObjectID

NSError *error = nil;
NSArray *cars = [myContext executeFetchRequest:allCars error:&error];
[allCars release];
//error handling goes here
for (NSManagedObject *car in cars) {
  [myContext deleteObject:car];
}
NSError *saveError = nil;
[myContext save:&saveError];
//more error handling here
Pakistan answered 5/9, 2009 at 15:49 Comment(30)
I would also configure the fetch to only retrieve the NSManagedObjectID to reduce any overhead from loading in the full object structure.Logical
It's not obvious how to only fetch the NSMangagedObjectID.. use [allCars setIncludesPropertyValues:NO]; (and don't bother hunting around for how to make an NSPropertyDescription for the object ID!)Westerfield
Just a heads up.. the code above wouldn't work for me unless I passed the executeFetchRequest an 'error:&error' too.Folkrock
Is there a faster way to do this with one command? Like in SQL you could do something like, DROP TABLE entity_name. But, 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.Headstock
@Matt no, because you're not dealing with a database. You're dealing with a graph of objects, and if you want to destroy all the objects, you have to destroy them all individually.Pakistan
@Matt it would be easiest if Dave updated his answer with that addition. Code does not show up well in comments.Logical
sorry for newbie question: do you need to save the context after the end of the for loop? eg [myContext save];Loan
@Loan yes you need to save the context. developer.apple.com/library/ios/#documentation/Cocoa/Conceptual/… ...Just as a new object is not saved to the store until the context is saved, a deleted object is not removed from the store until the context is saved.Removed
Any new facility in Core Data to make this more efficient? This is a serious issue for my app already far down the road porting to Core Data. Its taking multiple seconds to delete all 4000 entries from just one of several tables. This is too long for the user to wait. Same request directly with sqlite seems instantaneous.Grammarian
@David: If you want/need a database, use a database. Nobody stops you from using sqlite directly and forgo CoreData altogether. CoreData is for storing object graphs, it has nothing to do with database, since the backing storage doesn't have to be sqlite at all, it can also be XML or Apple's own binary format. Using CoreData where a database is required is the wrong approach to begin with.Speedwriting
@Mecki: after having ported much of the app to core data I did decide to switch to SQLite/fmdb instead. The object graph vs. database still isn't that clear a distinction to me. You can certainly do the same thing in either. Predicates are a generalized form of SQL. Relationships replace joins. But I think the fundamental point is how you think of your data. As data or as a graph of objects. My app is definitely on the data side.Grammarian
@David: As I wrote, CoreData does not necessarily store data in a database (that is only one option), it can also store them in an XML file and certain operations that you certainly expect from every database cannot easily be performed on an XML tree. If you are dealing with a huge amount of data, dump data and not complex object relationships, using a database directly is a much better choice; it will be faster, simpler and offers more powerful operations.Speedwriting
Drastic change happened in my case, thanks for the post and awesome answerIaea
@Mecki, I agree with your statement that we shouldn't think of Core Data as a database. That doesn't mean though that they can't add a deleteAll command that accepts a predicate. Regardless of SQLite or XML storage it is inefficient to perform these delete operations by looping through the individual objects and calling deleteObject. Not to mention bad for performance.Ptolemaeus
In order to get this to work, I had to also save the persistent store, as in [myContext saveToPersistentStore:&error].Conway
The question asks for the "quickest" way. Is this really the quickest way?Sweetscented
This does not clear my Many-To-Many relationships in SQLite and a every clear my performance are getting worse.Blanco
@Benjohn: just delete the line that calls -release and you're done.Pakistan
:-) I wanted to check if you were happy for me to make the edit. I've made it – I hope that's what you meant.Whaleboat
This solution does not scale well while dealing with large records.Chivalrous
@Chivalrous If by "large records" you mean "tens of thousands of records", you're right, but this is the best you can do with Core Data. But if by "large records" you mean "records with lots of data", that's not correct; we tell it to not include property values, so we only get the managed object ID.Pakistan
@DaveDeLong How NSBatchDeleteRequest can trigger NSFetchedResultsController delegate? I try almost everything, but nothing happen.Hackery
@Hackery - did you ever manage to get NSFetchedResultsController delegate calls to take place after NSBatchDeleteRequest runs?Dustin
Why isn't there a proper class reference for NSBatchDeleteRequest? The closest I could find were developer.apple.com/reference/coredata/nsbatchdeleterequest and developer.apple.com/library/ios/documentation/CoreData/…Armanda
how do you get NSPersistentStoreCoordinator?Exosphere
can someone update answer for swift 3 no longer works there.Welcome
Read this before copy&paste. You should merge changes if you are using viewContext with those objects at the momentBackcross
Beware that if you have delete rules, e.g. a cascading delete, within the entity then batch deletes may fail (with an error message that "Delete rule is not supported for batch deletes").Alvis
This BatchDeletion doesn't work if you are using offset to iterate and delete set of records of an entity. say If we have to delete 10 records each time in a table if I use batch request with offset its not removing the records properly.Bursiform
@DaveDeLong myPersistentStoreCoordinator - where you created this object ? where you get ?Dodecasyllable
M
56

Reset Entity in Swift 3 :

func resetAllRecords(in entity : String) // entity = Your_Entity_Name
    {

        let context = ( UIApplication.shared.delegate as! AppDelegate ).persistentContainer.viewContext
        let deleteFetch = NSFetchRequest<NSFetchRequestResult>(entityName: entity)
        let deleteRequest = NSBatchDeleteRequest(fetchRequest: deleteFetch)
        do
        {
            try context.execute(deleteRequest)
            try context.save()
        }
        catch
        {
            print ("There was an error")
        }
    }
Morphology answered 13/5, 2017 at 11:49 Comment(1)
Dont forget to import the CoreData, otherwise NSFetchRequest & NSBatchDeleteRequest won't work :-)Debus
R
33

A little bit more cleaned and universal : Add this method :

- (void)deleteAllEntities:(NSString *)nameEntity
{
    NSFetchRequest *fetchRequest = [[NSFetchRequest alloc] initWithEntityName:nameEntity];
    [fetchRequest setIncludesPropertyValues:NO]; //only fetch the managedObjectID

    NSError *error;
    NSArray *fetchedObjects = [theContext executeFetchRequest:fetchRequest error:&error];
    for (NSManagedObject *object in fetchedObjects)
    {
        [theContext deleteObject:object];
    }

    error = nil;
    [theContext save:&error];
}
Rothermere answered 12/9, 2014 at 14:10 Comment(0)
C
16

For Swift 2.0:

class func clearCoreData(entity:String) {
  let fetchRequest = NSFetchRequest()
  fetchRequest.entity = NSEntityDescription.entityForName(entity, inManagedObjectContext: moc!)
  fetchRequest.includesPropertyValues = false
  do {
    if let results = try moc!.executeFetchRequest(fetchRequest) as? [NSManagedObject] {
      for result in results {
        moc!.deleteObject(result)
      }

      try moc!.save()
    }
  } catch {
    LOG.debug("failed to clear core data")
  }
}
Conservancy answered 21/9, 2015 at 9:36 Comment(0)
E
12

Swift 4, iOS 12 and Xcode 10 Update

100% working just cut & paste

Just put this function in relevant class and call this function self.deleteData() in viewDidLoad() or anywhere or under a function or a button so that by clicking a button all the data from entity should be deleted and replace the "myEntity" as your entity that you have defined in your core data

func deleteData() {
    let appDel:AppDelegate = (UIApplication.shared.delegate as! AppDelegate)
    let context:NSManagedObjectContext = appDel.persistentContainer.viewContext
    let fetchRequest = NSFetchRequest<NSFetchRequestResult>(entityName: "myEntity")
    fetchRequest.returnsObjectsAsFaults = false         
    do {
        let results = try context.fetch(fetchRequest)
        for managedObject in results {
            if let managedObjectData: NSManagedObject = managedObject as? NSManagedObject {
                context.delete(managedObjectData)
            }
        }
    } catch let error as NSError {
        print("Deleted all my data in myEntity error : \(error) \(error.userInfo)")
    }
}
Exorcist answered 17/1, 2018 at 5:18 Comment(5)
Thank you, but why NSBatchDeleteRequest concept os not working? any idea.Weathercock
@SureshDurishetti have you imported CoreData in your class?Exorcist
Yes, added CoreDate. But no luck.Weathercock
You forgot to add call save on the context, add context.save() and you're good to goCecillececily
Yes, this require to save context otherwise no change will happenRothko
G
11

This is a similar question to the one here and someone suggested setting up a relationship delete rule so you only have to delete one object. So if you have or can make an entity with a to-many relationship to the cars and set the delete rule to cascade when you delete the higher entity all the cars will be deleted as well. This may save some processing time since you don't have to do the steps involved with loading ALL the cars. In a larger data set this could be absolutely necessary.

Gildea answered 20/4, 2011 at 15:48 Comment(1)
I just tried this on my current project with about 600 core data objects. When I encapsulated them in another object with cascade it took about 9.1 sec to delete. If I used the method suggested by Dave about it takes about 8.7 sec to delete. Not a notable difference for me.Mirza
M
11

Swift:

let fetchRequest = NSFetchRequest()
fetchRequest.entity = NSEntityDescription.entityForName(entityName, inManagedObjectContext: context)
fetchRequest.includesPropertyValues = false

var error:NSError?
if let results = context.executeFetchRequest(fetchRequest, error: &error) as? [NSManagedObject] {
    for result in results {
        context.deleteObject(result)
    }

    var error:NSError?
    if context.save(&error) {
        // do something after save

    } else if let error = error {
        println(error.userInfo)
    }

} else if let error = error {
    println("error: \(error)")
}
Muffin answered 17/6, 2015 at 10:22 Comment(1)
This answer should be updated with the new try/catch error handlingCommemorate
U
8

A good answer was already posted, this is only a recommendation!

A good way would be to just add a category to NSManagedObject and implement a method like I did:

Header File (e.g. NSManagedObject+Ext.h)

@interface NSManagedObject (Logic)

+ (void) deleteAllFromEntity:(NSString*) entityName;

@end

Code File: (e.g. NSManagedObject+Ext.m)

@implementation NSManagedObject (Logic)

+ (void) deleteAllFromEntity:(NSString *)entityName {
    NSManagedObjectContext *managedObjectContext = [AppDelegate managedObjectContext];
    NSFetchRequest * allRecords = [[NSFetchRequest alloc] init];
    [allRecords setEntity:[NSEntityDescription entityForName:entityName inManagedObjectContext:managedObjectContext]];
    [allRecords setIncludesPropertyValues:NO];
    NSError * error = nil;
    NSArray * result = [managedObjectContext executeFetchRequest:allRecords error:&error];
    for (NSManagedObject * profile in result) {
        [managedObjectContext deleteObject:profile];
    }
    NSError *saveError = nil;
    [managedObjectContext save:&saveError];
}

@end

... the only thing you have to is to get the managedObjectContext from the app delegate, or where every you have it in ;)

afterwards you can use it like:

[NSManagedObject deleteAllFromEntity:@"EntityName"];

one further optimization could be that you remove the parameter for tha entityname and get the name instead from the clazzname. this would lead to the usage:

[ClazzName deleteAllFromEntity];

a more clean impl (as category to NSManagedObjectContext):

@implementation NSManagedObjectContext (Logic)

- (void) deleteAllFromEntity:(NSString *)entityName {
    NSFetchRequest * allRecords = [[NSFetchRequest alloc] init];
    [allRecords setEntity:[NSEntityDescription entityForName:entityName inManagedObjectContext:self]];
    [allRecords setIncludesPropertyValues:NO];
    NSError * error = nil;
    NSArray * result = [self executeFetchRequest:allRecords error:&error];
    for (NSManagedObject * profile in result) {
        [self deleteObject:profile];
    }
    NSError *saveError = nil;
    [self save:&saveError];
}

@end

The usage then:

[managedObjectContext deleteAllFromEntity:@"EntityName"];
Ultimo answered 10/12, 2014 at 10:15 Comment(4)
Sorry, but [AppDelegate managedObjectContext] is not necessarily a "clean architecture".. ;-)Brach
Ok, true. Its code above is based on one managedObjectContext. the primary one ;) In multithreaded code i normally merge the main MOC of the app delegate to the othersUltimo
@DanielRinser can be deleteAllFromEntity: inManagedObjectContext:Hardtack
Yes. Better would be to change the deleteAllFromEntity method from a class method to an object method. then you can call the deleteAllFromEntity directly on an MOC instance.Ultimo
S
7

iOS 10 and later

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) ->()) {
        let context = NSManagedObjectContext()
        context = your 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)")
        }
    }
Stalker answered 2/3, 2017 at 12:23 Comment(1)
Thanks for posting your answer. That works for me. But you shouldn't just copy & paste your code here. For a newbee it is not clear what your CoreDataStack() or DataController() classes are. An update would be appreciated ;)Elm
L
6

Swift 4, iOS 10+
Static function which can apply for any entity to remove all of its data

protocol NSManagedObjectHelper {
}
extension NSManagedObject: NSManagedObjectHelper {
}
extension NSManagedObjectHelper where Self: NSManagedObject {
    static func removeAllObjectsInContext(_ managedContext: NSManagedObjectContext) {
        let request: NSFetchRequest = NSFetchRequest(entityName: String(describing: self))
        let deleteRequest = NSBatchDeleteRequest(fetchRequest: request)
        do {
            deleteRequest.resultType = .resultTypeObjectIDs//to clear objects from memory
            let result = try managedContext.execute(deleteRequest) as? NSBatchDeleteResult
            if let objectIDArray = result?.result as? [NSManagedObjectID] {
                let changes = [NSDeletedObjectsKey : objectIDArray]
                /*By calling mergeChangesFromRemoteContextSave, all of the NSManagedObjectContext instances that are referenced will be notified that the list of entities referenced with the NSManagedObjectID array have been deleted and that the objects in memory are stale. This causes the referenced NSManagedObjectContext instances to remove any objects in memory that are loaded which match the NSManagedObjectID instances in the array.*/
                NSManagedObjectContext.mergeChanges(fromRemoteContextSave: changes, into: [managedContext])
            }
            try managedContext.save()
        } catch let error {
            print(error)
        }
    }
}

'Room' is an entity

Room.removeAllObjectsInContext(self.persistentContainer.viewContext)

Edited on 20191025: the "Self.fetchRequest()" instruction may cause issue if we use multiple target in same projects. So replaced with NSFetchRequest(entityName: String(describing: self))

Lohner answered 13/2, 2018 at 13:46 Comment(0)
S
5

Swift 3.X and Swift 4.X , Easy way. Change only YourTable

    let fetchRequest = NSFetchRequest<NSFetchRequestResult>(entityName: "YourTable")
    fetchRequest.returnsObjectsAsFaults = false

    do
    {
        let results = try context.fetch(fetchRequest)
        for managedObject in results
        {
            let managedObjectData:NSManagedObject = managedObject as! NSManagedObject
            context.delete(managedObjectData)
        }
    } catch let error as NSError {
        print("Detele all my data in \(entity) error : \(error) \(error.userInfo)")
    }
Schismatic answered 9/11, 2017 at 11:24 Comment(1)
Also You can use this construction: let fetchRequest:NSFetchRequest<NSFetchRequestResult> = YourTable.fetchRequest()Ashtonashtonunderlyne
U
4

Extending Dave Delong's answer.

Swift Version that takes care of iOS 9 and previous versions as well. I have also covered Error handling in this:

let appDelegate: AppDelegate = UIApplication.sharedApplication().delegate as! AppDelegate

    let fetchRequest = NSFetchRequest(entityName: "Car")
    if #available(iOS 9.0, *) {
        let delete = NSBatchDeleteRequest(fetchRequest: fetchRequest)
        do {
            try appDelegate.persistentStoreCoordinator.executeRequest(delete, withContext: appDelegate.managedObjectContext)
        } catch let error as NSError {
            print("Error occured while deleting: \(error)")
        }
    } else {
        // Fallback on earlier versions
        let carRequest = NSFetchRequest()
        carRequest.entity = NSEntityDescription.entityForName("Cars", inManagedObjectContext: appDelegate.managedObjectContext)
        carRequest.includesPropertyValues = false

        do {
            let cars: NSArray = try appDelegate.managedObjectContext.executeFetchRequest(carRequest)

            for car in cars {
                appDelegate.managedObjectContext.delete(car)
            }

            try appDelegate.managedObjectContext.save()

        } catch let error as NSError {
            print("Error occured while fetching or saving: \(error)")
        }
    }
Underpainting answered 21/1, 2016 at 6:13 Comment(1)
upvoted . ios 9 way of deleting the records is really awsm .Abarca
F
4

Swift4+ and Xcode 10+ Use below code for delete all records from entity.

func deleteAllRecords(entity : String) {

        let managedContext = CoreDataManager.sharedManager.persistentContainer.viewContext //your context
        let deleteFetch = NSFetchRequest<NSFetchRequestResult>(entityName: entity)
        let deleteRequest = NSBatchDeleteRequest(fetchRequest: deleteFetch)
        
        do {
            try managedContext.execute(deleteRequest)
            try managedContext.save()
        } catch {
            print ("There was an error")
        }
    }

How to use

self.deleteEntityData(entity: "YOUR_ENTITY_NAME")
Formless answered 1/9, 2022 at 12:31 Comment(1)
The above code does not update in SwiftUI, can you provide the SwiftUI version?Phoney
B
3

quick purge of all objects in DB:

func purgeAllData() {
    let uniqueNames = persistentContainer.managedObjectModel.entities.compactMap({ $0.name })

    uniqueNames.forEach { (name) in
      let fetchRequest = NSFetchRequest<NSFetchRequestResult>(entityName: name)
       let batchDeleteRequest = NSBatchDeleteRequest(fetchRequest: fetchRequest)
         do {
        try persistentContainer.viewContext.execute(batchDeleteRequest)
      } catch {
        let nserror = error as NSError
        fatalError("Unresolved error \(nserror), \(nserror.userInfo)")
      }
   }
 }
Backler answered 23/5, 2019 at 9:45 Comment(0)
P
3

SwiftUI

fetch instances from your entity, and loop to delete every one.

@Environment(\.managedObjectContext) var moc
    
@FetchRequest(sortDescriptors: []) var wizards: FetchedResults<Wizard>

var body: some View {
    VStack {
        List() { }

        Button("Delete all") {
            for wizard in wizards {
                moc.delete(wizard)
            }
            
            if moc.hasChanges {
                try? moc.save()
            }
        }
    }
}

Paiz answered 23/5, 2022 at 16:59 Comment(1)
In SwiftUI, if use NSBatchDeleteRequest(fetchRequest: fetch) to delete, the UI will not be updated. Is there any way to update it?Phoney
E
2

Why not fold in the data that you receive with the existing cache? Otherwise it's not really 'refreshing', it's 'starting again' and you might as well drop/delete the SQLLite file and start again (assuming you're not persisting other data as well).

Empathize answered 5/9, 2009 at 15:33 Comment(1)
Bad solution. If there are other tables in the Sqlite database, we will obviously loose all that. This is more a hack for a particular solution and cannot be considered for the larger cases.Franky
N
2

the OOP way without any strings as entities names Swift 3+, Xcode 10+

func batchDelete<T>(in context: NSManagedObjectContext, fetchRequest: NSFetchRequest<T>) throws {
    guard let request = fetchRequest as? NSFetchRequest<NSFetchRequestResult> else {
        throw ErrorService.defaultError
    }
    let batchDeleteRequest = NSBatchDeleteRequest(fetchRequest: request)
    do {
        try context.execute(batchDeleteRequest)
    } catch {
        throw error
    }
}

then just call in do/catch block

    let fetchRequest: NSFetchRequest<YourEntity> = YourEntity.fetchRequest()
    do {
        let data = try context.fetch(fetchRequest)
        if data.count > 0 {
            try self.batchDelete(in: context, fetchRequest: fetchRequest)
        }
    } catch {
        // throw error
    }
Navaho answered 12/10, 2019 at 16:55 Comment(0)
L
1

if the entity contains a lot of entries the best way is like this because it saves memory

 - (void)deleteAll:(NSManagedObjectContext *)managedObjectContext entityName:(NSString *)entityName
{
    NSFetchRequest *fetchRequest = [[NSFetchRequest alloc] init];
    [managedObjectContext setUndoManager:nil];
    NSEntityDescription *entity = [NSEntityDescription entityForName:entityName inManagedObjectContext:managedObjectContext];
    [fetchRequest setEntity:entity];
    [fetchRequest setIncludesPropertyValues:NO];
    [fetchRequest setFetchLimit:100]; // you can change this number if you want
    NSError *error;
    NSArray *items = [managedObjectContext executeFetchRequest:fetchRequest error:&error];
    while ([items count] > 0) {
        @autoreleasepool {
            for (NSManagedObject *item in items) {
                [managedObjectContext deleteObject:item];
            }
            if (![managedObjectContext save:&error]) {
                NSLog(@"Error deleting %@ - error:%@",self.entityName, error);
            }
        }
        items = [managedObjectContext executeFetchRequest:fetchRequest error:&error];
    }
}
Lurlenelurline answered 25/2, 2015 at 17:35 Comment(0)
H
1

iOS 9.0 and Later :

NSBatchDeleteRequest is used to delete records in core data. It works very fast and takes less time to delete all records from an entity. It requires NSFetchRequest in argument. If you want to delete all records from an entity, you can use it and it works for me.

let manageObject:NSManagedObjectContext = appDelegateObject.managedObjectContext

let fetchRequest = NSFetchRequest(entityName: “EnityName”)

let deleteRequest = NSBatchDeleteRequest(fetchRequest: fetchRequest)

let persistCor:NSPersistentStoreCoordinator = appDelegateObject.persistentObject
 do {
        try persistCor.executeRequest(deleteRequest, withContext: manageObject)
        try manageObject.save()
    } catch {
        print(error?.localizedDescription)
    }
Herniotomy answered 17/10, 2016 at 11:15 Comment(0)
S
1

In Swift 3.0

 func deleteAllRecords() {
        //delete all data
        let context = appDelegate.persistentContainer.viewContext

        let deleteFetch = NSFetchRequest<NSFetchRequestResult>(entityName: "YourClassName")
        let deleteRequest = NSBatchDeleteRequest(fetchRequest: deleteFetch)

        do {
            try context.execute(deleteRequest)
            try context.save()
        } catch {
            print ("There was an error")
        }
    }
Smackdab answered 10/11, 2017 at 6:18 Comment(0)
S
1

This code will work for both iOS 9 and below

class func deleteAllRecords(in entity : String) // entity = Your_Entity_Name
    {

        let context = CoreDataStack.getContext() // Note:- Replace your context here with CoreDataStack.getContext()
        let deleteFetch = NSFetchRequest<NSFetchRequestResult>(entityName: entity)
        if #available(iOS 9, *)
        {
            let deleteRequest = NSBatchDeleteRequest(fetchRequest: deleteFetch)
            do
            {
                try context.execute(deleteRequest)
                try context.save()
            }
            catch
            {
                print("There was an error:\(error)")
            }
        }
        else
        {
            do{
                let deleteRequest = try context.fetch(deleteFetch)
                for anItem in deleteRequest {
                    context.delete(anItem as! NSManagedObject)
                }
            }
            catch
            {
                print("There was an error:\(error)")
            }
        }
        CoreDataStack.saveContext() // Note:- Replace your savecontext here with CoreDataStack.saveContext()
    }
Sop answered 25/6, 2018 at 8:14 Comment(0)
D
0

Dave Delongs's Swift 2.0 answer was crashing for me (in iOS 9)

But this worked:

let fetchRequest = NSFetchRequest(entityName: "Car")
let deleteRequest = NSBatchDeleteRequest(fetchRequest: fetchRequest)

    do {
        try managedObjectContext.executeRequest(deleteRequest)
        try managedObjectContext.save()
    }
    catch let error as NSError {
       // Handle error
    }
Duress answered 27/1, 2016 at 20:30 Comment(0)
A
0

Swift 3 solution with iOS 9 'NSBatchDeleteRequest' and fallback to earlier iOS versions implemented as an extension on 'NSManagedObjectContext'. Apple reference https://developer.apple.com/library/content/featuredarticles/CoreData_Batch_Guide/BatchDeletes/BatchDeletes.html

extension NSManagedObjectContext {
    func batchDeleteEntities<T: NSManagedObject>(ofType type: T.Type) throws {
        let fetchRequest = NSFetchRequest<NSFetchRequestResult>(entityName: String(describing: type.self))
        if #available(iOS 9.0, *) {
            let request = NSBatchDeleteRequest(fetchRequest: fetchRequest)
            let result = try execute(request) as? NSBatchDeleteResult
            if let objectIDArray = result?.result as? [NSManagedObjectID] {
                let changes = [NSDeletedObjectsKey: objectIDArray]
                NSManagedObjectContext.mergeChanges(fromRemoteContextSave: changes, into: [self])
            }
        } else {
            fetchRequest.includesPropertyValues = false
            let results = try fetch(fetchRequest)
            if let actualResults = results as? [NSManagedObject], !actualResults.isEmpty {
                actualResults.forEach { delete($0) }
            }
        }
    }
}
Atherosclerosis answered 23/4, 2017 at 20:28 Comment(0)
U
0

Use NSBatchDeleteRequest to delete multiple records If Minimum iOS is 9.0. If background thread, execute NSManagedObjectContext save else use NSFetchRequest to get records and delete all records in for loop and Save once deletion done.

Unscramble answered 12/12, 2017 at 15:13 Comment(0)
C
0

in iOS 11.3 and Swift 4.1

let fetchRequest = NSFetchRequest<NSFetchRequestResult>(entityName: entityName)
        let batchDeleteRequest = NSBatchDeleteRequest(fetchRequest: fetchRequest )
        batchDeleteRequest.resultType = .resultTypeCount
        do {
            let batchDeleteResult = try dataController.viewContext.execute(batchDeleteRequest) as! NSBatchDeleteResult
            print("The batch delete request has deleted \(batchDeleteResult.result!) records.")
            dataController.viewContext.reset() // reset managed object context (need it for working)
        } catch {
            let updateError = error as NSError
            print("\(updateError), \(updateError.userInfo)")
        }

you have to call reset after you do execute. If not, it will not update on the table view.

Caritacaritas answered 4/4, 2018 at 17:30 Comment(0)
T
0
    func deleteAll(entityName: String) {

    let fetchRequest = NSFetchRequest<NSFetchRequestResult>(entityName: entityName)
    let deleteRequest = NSBatchDeleteRequest(fetchRequest: fetchRequest)
    deleteRequest.resultType = .resultTypeObjectIDs
    guard let context = self.container?.viewContext
        else { print("error in deleteAll")
            return }

    do {
        let result = try context.execute(deleteRequest) as? NSBatchDeleteResult
        let objectIDArray = result?.result as? [NSManagedObjectID]
        let changes: [AnyHashable : Any] = [NSDeletedObjectsKey : objectIDArray as Any]
        NSManagedObjectContext.mergeChanges(fromRemoteContextSave: changes, into: [context])
    } catch {
        print(error.localizedDescription)
    }
}
Tanner answered 13/4, 2019 at 5:28 Comment(0)
A
0

The above answers give a good insight on how to delete the "Cars"

However, I want this answer to challenge the approach itself:

1- SQLite CoreData is a relational database. In this case, where there isn't any releation, I would advise against using CoreData and maybe using the file system instead, or keep things in memory.

2- In other examples, where "Car" entity have other relations, and therefore CoreData, I would advise against having 2000 cars as root entity. Instead I would give them a parent, let's say "CarsRepository" entity. Then you can give a one-to-many relationship to the "Car" entity, and just replace the relationship to point to the new cars when they are downloaded. Adding the right deletion rule to the relationships ensures the integrity of the model.

Anthropopathy answered 23/11, 2020 at 20:40 Comment(0)
L
0

NSBatchDeleteRequest Swift 5.5 and Xcode 13.2

deletes the objects in the SQLite persistent store without loading into memory. The changes enacted on the persistent store are not reflected in the objects that are currently in memory.

After a batch delete has been executed, remove any objects in memory that has been deleted from the persistent store.

below are some handy extensions methods that perform the batchDeleteRequest

extension NSManagedObject {
    
    private static var entityName: String {
        return String(describing: self)
    }
    
    static func fetchRequest<Self>(
        with predicate: NSPredicate? = nil,
        configureBlock: ((NSFetchRequest<Self>) -> Void)? = nil
    ) -> NSFetchRequest<Self> where Self: NSFetchRequestResult {
        let request = NSFetchRequest<Self>(entityName: entityName)
        request.predicate = predicate
        configureBlock?(request)
        return request
    }
    
    static func batchDelete(with fetchRequest: NSFetchRequest<NSFetchRequestResult>,
                            in context: NSManagedObjectContext) {
        let batchDeteleRequest = NSBatchDeleteRequest(fetchRequest: fetchRequest)
        batchDeteleRequest.resultType = .resultTypeObjectIDs
        do {
            if let fetchResult = try context.execute(batchDeteleRequest) as? NSBatchDeleteResult,
               let deletedManagedObjectIds = fetchResult.result as? [NSManagedObjectID], !deletedManagedObjectIds.isEmpty {
                let changes = [NSDeletedObjectsKey: deletedManagedObjectIds]
                NSManagedObjectContext.mergeChanges(fromRemoteContextSave: changes, into: [context])
            }
        } catch {
            print("Error while executing batchDeleteRequest: \(error.localizedDescription)")
        }
    }
}

Example: We can batch delete the Entity by calling batchDelete static method by passing the fetchRequest

class Entity: NSManagedObject {
    @NSManaged var name: String?
    @NSManaged var value: String?
}

extension Entity {
    
    static func executeBatchDelete(in context: NSManagedObjectContext) {
        let predicate = NSPredicate(format: "\(#keyPath(Entity.value)) == %@)", "abc")
        let deleteRequest: NSFetchRequest<NSFetchRequestResult> = Entity.fetchRequest(with: predicate)
        Entity.batchDelete(with: deleteRequest, in: context)
    }
}
Lollop answered 21/12, 2021 at 7:11 Comment(0)
I
-1

In Swift 2.0:

func deleteAllData(entity: String)
{
    let appDelegate = UIApplication.sharedApplication().delegate as! AppDelegate
    let managedContext = appDelegate.managedObjectContext
    let fetchRequest = NSFetchRequest(entityName: entity)
    fetchRequest.returnsObjectsAsFaults = false

    do 
    {
        let results = try managedContext.executeFetchRequest(fetchRequest)
        for managedObject in results
        {
            let managedObjectData:NSManagedObject = managedObject as! NSManagedObject
            managedContext.deleteObject(managedObjectData)
        }
    } catch let error as NSError {
        print("Detele all data in \(entity) error : \(error) \(error.userInfo)")
    }
}
Idiocrasy answered 24/5, 2016 at 4:35 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.