iOS CoreData update entity object
I'm implementing a car manager for an iPhone app and I have trouble saving a new car. So I have a "Car" entity (and per-loaded DB), containing multiples attributes. I have 2 booleans "saved" and "selected" to track which car the user added to his list (if added, saved = 1) and which car is currently selected. So when I create a new car, I deselect the old one (selected=0), and want to modify the new car to set its attributes saved=1 and selected=1.
Here is my functions:
- (IBAction)save
{
// Disable the previous car selection.
[self deselectCurrentSelectedCar];
// Add new car as saved and selected.
[self saveAndSelectNewCar];
// Call the delegate to dismiss the modal view.
[_delegate dismissAndSave];
}
- (void)deselectCurrentSelectedCar
{
// Fetched saved car.
NSFetchRequest *fetchRequest = [[NSFetchRequest alloc] init];
NSEntityDescription *entity = [NSEntityDescription entityForName:@"Car" inManagedObjectContext:[self managedObjectContext]];
[fetchRequest setEntity:entity];
// Set predicate and sort orderings...
NSPredicate *predicate = [NSPredicate predicateWithFormat:@"selected = 1"];
[fetchRequest setPredicate:predicate];
// Execute the fetch -- create a mutable copy of the result.
NSError *error = nil;
NSMutableArray *mutableFetchResults = [[self.managedObjectContext executeFetchRequest:fetchRequest error:&error] mutableCopy];
if (mutableFetchResults == nil) {
// Handle the error.
NSLog(@"[AddCarViewController] deselect car: car not found.");
}
else {
// Get car and assign new selected value.
Car *carToSave = (Car *)[mutableFetchResults objectAtIndex:0];
[carToSave setSelected:[NSNumber numberWithInt:0]];
// Save the car.
NSError *error = nil;
if (![self.managedObjectContext save:&error]) {
// Handle the error.
NSLog(@"[AddCarViewController] deselect car: error saving car.");
}
else {
NSLog(@"[AddCarViewController] deselect car: car saved.");
}
}
// Memory management.
[fetchRequest release];
[mutableFetchResults release];
}
- (void)saveAndSelectNewCar
{
// Get the car, and pass to the delegate the new settings.
NSFetchRequest *fetchRequest = [[NSFetchRequest alloc] init];
NSEntityDescription *entity = [NSEntityDescription entityForName:@"Car" inManagedObjectContext:[self managedObjectContext]];
[fetchRequest setEntity:entity];
// Set predicate and sort orderings...
NSPredicate *predicate = [NSPredicate predicateWithFormat:@"(year=%@) AND (make=%@) AND (model=%@) AND (d=%@) AND (n=%@)", _car.year, _car.make, _car.model, _car.d, _car.n];
[fetchRequest setPredicate:predicate];
// Execute the fetch -- create a mutable copy of the result.
NSError *error = nil;
NSMutableArray *mutableFetchResults = [[self.managedObjectContext executeFetchRequest:fetchRequest error:&error] mutableCopy];
if (mutableFetchResults == nil) {
// Handle error.
NSLog(@"[AddCarViewController] save and select: can't save the new car");
}
else {
// Get the car selected.
Car *selectedCar = (Car *)[mutableFetchResults objectAtIndex:0];
[selectedCar setValue:[NSNumber numberWithInt:1] forKey:@"selected"];
[selectedCar setValue:[NSNumber numberWithInt:1] forKey:@"saved"];
// Save the car.
NSError *error = nil;
if (![self.managedObjec开发者_开发百科tContext save:&error]) {
// Handle the error.
NSLog(@"[AddCarViewController] save and select: error saving car.");
}
else {
NSLog(@"[AddCarViewController] save and select: car saved.");
}
// Add car to delegate.
[EcoAppAppDelegate setUserCar:selectedCar];
}
// Memory management.
[fetchRequest release];
[mutableFetchResults release];
}
And I have this log all the time: "error saving car." on both functions. So there is definitely something wrong.
Also, it's pretty anoying to fetch the car I want to modify it, instead of doing right away an update. If there another please tell me!
Thanks.
In your header file, you should set up a mutable array for your cars.
NSMutableArray *carArray;
and
@property (nonatomic, retain) NSMutableArray *carArray;
Then make sure to synthesize it in your implementation file. Then when you fetch from your managed object context, you can set your array with the contents returned
NSFetchRequest *fetchRequest = [[NSFetchRequest alloc] init];
NSEntityDescription *entity = [NSEntityDescription entityForName:@"Car" inManagedObjectContext:[self managedObjectContext]];
[fetchRequest setEntity:entity];
// Execute the fetch -- create a mutable copy of the result.
NSError *error = nil;
NSMutableArray *mutableFetchResults = [[self.managedObjectContext executeFetchRequest:fetchRequest error:&error] mutableCopy];
if (mutableFetchResults == nil) {
// Handle the error.
NSLog(@"[AddCarViewController] deselect car: car not found.");
} else {
[self setCarArray:mutableFetchResults];
}
Doing this will hold onto all the objects in your managed object context, so when you want to modify a Car, you can find it there instead of fetching again. If you need to sort it, you can apply a sort descriptor initialized with one of your attributes as a key. For example:
NSSortDescriptor *sorter = [NSSortDescriptor sortDescriptorWithKey:@"selected" ascending:YES];
[carArray sortUsingDescriptors:[NSArray arrayWithObject:sorter]];
This will sort the Cars based on whether they are selected or not.
As for why you're getting an error, that could be one of many reasons. Typically the MOC will fail to save if one of your attributes is set to nil, so that might be the cause. You can get some detail from it if you set something like the following up
if (![self.managedObjectContext save:&error]) {
NSLog(@"failed with error %@", error);
}
This will return the actual error you ran into. It would also be a good idea to set up a log to make sure you have Car specified. Something like NSLog(@"selected car %@", carToSave);
just to be safe
精彩评论