21

I know how to delete a single object in CoreData I'm just wondering if theres a simpler way of deleting multiple objects?

For single delete you can use

[moc deleteObject:someManagedObject];

but there is no equivalent for multiple objects.

At the moment I'm thinking of doing...

NSArray *arrayOfManagedObjectsToDelete = //...

for (SomeManagedObjectClass *managedObject in arrayOfManagedObjectsToDelete) {
    [moc deleteObject:managedObject];
}

but I wasn't sure if there was another way of doing this?

ideally a method like...

- (void)deleteObjects:(NSSet*)objects

on NSManagedObjectContext or some similar method.

Martin R
  • 529,903
  • 94
  • 1,240
  • 1,382
Fogmeister
  • 76,236
  • 42
  • 207
  • 306
  • http://stackoverflow.com/questions/1383598/core-data-quickest-way-to-delete-all-instances-of-an-entity – Hugo May 02 '13 at 01:42

5 Answers5

22

iOS 9 and later

Swift

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

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

Objective-C

NSFetchRequest *request = [[NSFetchRequest alloc] initWithEntityName:@"EntityName"];
NSBatchDeleteRequest *deleteRq = [[NSBatchDeleteRequest alloc] initWithFetchRequest:request];

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

iOS 8 and older

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

NSError *error = nil;
NSArray *objects = [myContext executeFetchRequest:fr error:&error];

//error handling goes here
for (NSManagedObject *object in objects) {
  [myContext deleteObject:object];
}
NSError *saveError = nil;
[myContext save:&saveError];
//more error handling here
Johnykutty
  • 12,091
  • 13
  • 59
  • 100
ZaEeM ZaFaR
  • 1,508
  • 17
  • 22
  • Is it save to do it in background `NSOperation` if we have private `NSManagedObjectContext`? (And we get persistentStoreCoordinator from that context by it's property `persistentStoreCoordinator`) – Dima Deplov May 18 '16 at 11:26
  • Yes, as long as you take care for merge changes policy just like you do for other MOC changes. – ZaEeM ZaFaR May 19 '16 at 06:42
  • 1
    This deletes all objects, the question was how to delete a couple of items. – JKvr Jan 19 '17 at 07:42
  • It seems that the iOS 9 example disregard the Cascade delete rule. – LShi Mar 09 '17 at 04:48
  • 2
    Note that NSBatchDeleteRequest doesn't trigger notifications and you should also invalidate the context after it, as it changes directly the store... – User Sep 19 '17 at 14:48
13

iOS10 & Swift 3

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

    do{
        try mContext.execute(deleteRequest)
    }catch let error as NSError {//handle error here }

This deletes all the objects of EntityName but you can apply additional filtering with NSPredicate

Chris Balavessov
  • 805
  • 8
  • 14
  • @Fogmeister, The reason why I posted this is that the current highest ranked answer doesn't build in Swift 3 and iOS 10. Also, calling the method on NSManagedObjectContext is in my opinion preferable. – Chris Balavessov May 23 '17 at 20:57
  • 1
    Sorry, I down voted too quickly. I thought it was the usual "Here is the other answer but slightly changed to Swift 3" type of answer. Accepted this answer now as it actually improves on the current answer. Thanks :D – Fogmeister May 24 '17 at 11:29
  • 1
    Note that NSBatchDeleteRequest doesn't trigger notifications and you should also invalidate the context after it, as it changes directly the store... – User Sep 19 '17 at 14:46
7

As I know, there isn't a method for that... You should do like you're already doing. There is a method called deletedObjects but it just returns the set of objects that will be removed from their persistent store during the next save operation, as described in class reference.

CainaSouza
  • 1,417
  • 2
  • 16
  • 31
5

No, there is no specific method to remove multiple objects atm. But I would do something like this, simillar to what you already are doing:

- (void)removeFromManagedObjectContext {
  NSFetchRequest *fetchRequest = [[NSFetchRequest alloc] init];
    fetchRequest.entity = [NSEntityDescription entityForName:@"YourEntity" inManagedObjectContext:managedObjectContext];

    NSArray *results = [managedObjectContext executeFetchRequest:fetchRequest error:nil];

 
  
    for (Your Entity *Entity in results) {
        [managedObjectContext deleteObject:Entity];
    }
}
0

From https://www.avanderlee.com/swift/nsbatchdeleterequest-core-data/

extension NSManagedObjectContext {
    
    /// Executes the given `NSBatchDeleteRequest` and directly merges the changes to bring the given managed object context up to date.
    ///
    /// - Parameter batchDeleteRequest: The `NSBatchDeleteRequest` to execute.
    /// - Throws: An error if anything went wrong executing the batch deletion.
    public func executeAndMergeChanges(using batchDeleteRequest: NSBatchDeleteRequest) throws {
        batchDeleteRequest.resultType = .resultTypeObjectIDs
        let result = try execute(batchDeleteRequest) as? NSBatchDeleteResult
        let changes: [AnyHashable: Any] = [NSDeletedObjectsKey: result?.result as? [NSManagedObjectID] ?? []]
        NSManagedObjectContext.mergeChanges(fromRemoteContextSave: changes, into: [self])
    }
}

My goal is to delete some objects so here's how I use it

var objectsToRemove = [NSManagedObjectID]()
// gather objectIDs

let batchDeleteRequest = NSBatchDeleteRequest(objectIDs: objectsToRemove)
do {
    try defaultContext.executeAndMergeChanges(using: batchDeleteRequest)            
} catch {
    // handle error
}
Tanin
  • 585
  • 7
  • 10