19

I know how to use NSPredicate to perform a SQL SELECT-like operation. How can I perform something like DELETE WHERE? Do I have to call [NSManagedObjectContext deleteObject] for each fetched object? Thanks

NSError *error;

NSFetchRequest *request = [[NSFetchRequest alloc] init];
[request setEntity:[NSEntityDescription entityForName:TASK_ENTITY inManagedObjectContext:managedObjectContext]];

NSPredicate *predicate = [NSPredicate predicateWithFormat: @"label LIKE  %@", label];
[request setPredicate:predicate];

NSArray *array = [managedObjectContext executeFetchRequest:request error:&error];

[managedObjectContext deleteObject:[array objectAtIndex:0]];
1

5 Answers 5

6

I believe looping over the returned array and calling [NSManagedObjectContext deleteObject:] is the "correct"/idiomatic way to do it. It might seem inefficient, but remember that the fetch command doesn't actually fetch the objects' data, and the deleteObject: method just marks the object for deletion, which gets applied when you send [NSManagedObjectContext save:]. Not knowing the internals of Core Data I can't tell you whether it's as efficient as a DELETE WHERE query (presumably Core Data has the indexed primary keys in memory from the fetch, and uses those) but in my experience with profiling Core Data apps it's not significantly slower than saving new or updated objects.

Sign up to request clarification or add additional context in comments.

Comments

1

You can use NSBatchDeleteRequest available on iOS 9.0+, macOS 10.11+, tvOS 9.0+, watchOS 2.0+

NSPredicate *predicate = [NSPredicate predicateWithFormat:@"label LIKE  %@", label];
NSFetchRequest *fetchRequest = [TaskEntity fetchRequest];
[fetchRequest setPredicate:predicate];
// Create batch delete request
NSBatchDeleteRequest *deleteReq = [[NSBatchDeleteRequest alloc] initWithFetchRequest:fetchRequest];
NSError *error = nil;
NSBatchDeleteResult *deletedResult = [appDelegate.persistentContainer.viewContext executeRequest:deleteReq error:&error];
if (error) {
  NSLog(@"Unable to delete the data");
}
else {
  NSLog(@"%@ deleted", deleteReq.result);
}

Swift code (from the above link)

let fetch = NSFetchRequest<NSFetchRequestResult>(entityName: "Employee")
fetch.predicate = NSPredicate(format: "terminationDate < %@", NSDate())
let request = NSBatchDeleteRequest(fetchRequest: fetch)

do {
    let result = try moc.execute(request)
} catch {
    fatalError("Failed to execute request: \(error)")
}

NOTE:

I found below comment about execute of moc

Method to pass a request to the store without affecting the contents of the managed object context.

Which means any unsaved data in moc won't be affected. i.e. if you've created/updated entity that falls in the delete request criteria and don't called save on moc then that object won't be deleted.

Comments

0

I haven't found an other way than to use an NSArray method for deletion.
(If there is I want to know about it)
You could nest the call to have it on one line if you really don't wan't to store the array. But if you do so verify what is the return of the Fetch in case of an error.

makeObjectsPerformSelector :
Sends to each object in the array the message identified by a given selector, starting with the first object and continuing through the array to the last object.
- (void)makeObjectsPerformSelector:(SEL)aSelector

Or there is a block one to that is suppose to be faster.

Comments

0

I just tried this and it is successful:

NSError *error = nil;
NSFetchRequest* fetchrequest = [NSFetchRequest fetchRequestWithEntityName:@"EntityName"];
[request setPredicate:[NSPredicate predicateWithFormat:@"attribute == %@", variable]];
NSArray *deleteArray = [context executeFetchRequest:fetchrequest error:&error];

if (deleteArray != nil)
{
    for (NSManagedObject* object in deleteArray)
    {
        [context deleteObject:object];

        //Reload/refresh table or whatever view..
    }

    [context save:&error];
}

Comments

0
NSFetchRequest *fetchRequest = [[NSFetchRequest alloc] init];
[fetchRequest setEntity:[NSEntityDescription entityForName:TASK_ENTITY inManagedObjectContext:managedObjectContext];

[fetchRequest setPredicate:[NSPredicate predicateWithFormat:@"label LIKE%@", label.text]];

NSError* error = nil;

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

if(![results count]==0)
{
   [managedObjectContext deleteObject:[results objectAtIndex:0]];
}
if (![managedObjectContext save:&error]) {
    NSLog(@"Whoops, couldn't save: %@", [error localizedDescription]);
}

Comments

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.