Reputation: 8288
I have an entity called 'Job' with two boolean attributes named 'completed' and 'logged'. I am trying to retrieve all completed jobs that have not been logged at app start-up and change them to logged. I'm able to get all the completed but unlogged jobs with this fetchRequest:
NSPredicate *predicate = [NSPredicate predicateWithFormat:@"(completed == %@ && logged == %@)", [NSNumber numberWithBool:YES], [NSNumber numberWithBool:NO]];
I'm then assigning this predicate to a fetchRequest and calling the [managedObjectContext executeFetchRequest:fetchRequest] method to get an array of all Job entities that meet this criteria. This seems to work fine and is returning the correct number of jobs.
What I've been trying to do is loop through the NSArray returned, set the logged attribute to YES and then save. This seems to complete and doesn't return any errors but the changes are not persisted when the application quits. Where am I going wrong?
[fetchRequest setPredicate:predicate];
NSError error;
NSArray jobsToLog = [managedObjectContext executeFetchRequest:fetchRequest error:&error];
if ([jobsToLog count] > 0) {
for (int i = 0; i < [jobsToLog count] - 1; i++) {
[[jobsToLog objectAtIndex:i] setLogged:[NSNumber numberWithBool:YES]];
// Commit the changes made to disk
error = nil;
if (![managedObjectContext save:&error]) {
// An error occurred
}
}
}
Thanks in anticipation,
Upvotes: 0
Views: 336
Reputation: 46718
First, you can clean things up a bit via:
[fetchRequest setPredicate:predicate];
NSError *error = nil;
NSArray jobsToLog = [managedObjectContext executeFetchRequest:fetchRequest error:&error];
NSAssert1(error == nil, @"Error retrieving jobs: %@", [error userInfo]);
for (id job in jobsToLog) {
[job setValue:[NSNumber numberWithBool:YES] forKey:@"logged"];
}
if (![managedObjectContext save:&error]) {
NSAssert1(NO, @"Failed to save %@", [error userInfo]);
}
error
being nil and being a pointer (your declaration was not). If you do not then the initial state of that pointer is undefined and definitely not nil.Upvotes: 1
Reputation: 2480
Some notes that may help:
The for loop is looping from 0 to one less than the count. This will skip the last job. If there is only 1 job, nothing will happen. Change the loop to:
for (int i = 0; i < [jobsToLog count]; i++)
or
for (int i = 0; i <= [jobsToLog count] - 1; i++)
When pulling objects out of NSArray the compiler will not know its type. You should explicitly cast the object:
[(Job *)[jobsToLog objectAtIndex:i] setLogged:[NSNumber numberWithBool:YES]];
You can do both of the above using fast enumeration:
for(Job *thisJob in jobsToLog) {
[thisJob setLogged:[NSNumber numberWithBool:YES];
}
Upvotes: 1
Reputation: 19030
I'm no expert here but I think you need to tell the managed object context by using setPrimitiveValue: to make the changes. So try this.
[self willChangeValueForKey:@"logged"];
[self setPrimitiveValue:[NSNumber numberWithBool:YES] forKey:@"logged"];
[self didChangeValueForKey:@"logged"];
Upvotes: 0
Reputation: 25281
What if you use the KVC (Key Value Coding) method:
[[jobsToLog objectAtIndex:i] setValue:[NSNumber numberWithBool:YES] forKey:@"logged"];
Do you have a setLogged method in your custom NSManagedObject class?
Upvotes: 0