Fail to save a managed object to core-data after its properties were updated
I have no trouble to create the object, but updating it fails. Here is the creation code:
// Save data from pList to core data fro the first time
- (void) saveToCoreData:(NSDictionary *)plistDictionary {
// Create system parameter entity
SystemParameters *systemParametersEntity = (SystemParameters *)[NSEntityDescription
insertNewObjectForEntityForName:@"SystemParameters"
inManagedObjectContext:mManagedObjectContext];
////
// GPS SIMULATOR
////
NSDictionary *GpsSimulator = [plistDictionary valueForKey:@"GpsSimulator"];
[systemParametersEntity setMGpsSimulatorEnabled:[[GpsSimulator objectForKey:@"Enabled"] boolValue]];
[systemParametersEntity setMGpsSimulatorFileName:[GpsSimulator 开发者_如何学CvalueForKey:@"FileName"]];
[systemParametersEntity setMGpsSimulatorPlaybackSpeed:[[GpsSimulator objectForKey:@"PlaybackSpeed"] intValue]];
[self saveAction];
}
During execution the cached copy is changed and then it is saved (or trying) to the database. Here is the code to save the changed copy:
// Save data from pList to core data fro the first time
- (void) saveSystemParametersToCoreData:(SystemParameters *)theSystemParameters {
// Step 1: Select Data
NSFetchRequest *fetchRequest = [[NSFetchRequest alloc] init];
NSEntityDescription *entity = [NSEntityDescription entityForName:@"SystemParameters"
inManagedObjectContext:mManagedObjectContext];
[fetchRequest setEntity:entity];
NSError *error = nil;
NSArray *items = [self.managedObjectContext
executeFetchRequest:fetchRequest error:&error];
[fetchRequest release];
if (error) {
NSLog(@"CoreData: saveSystemParametersToCoreData: Unresolved error %@, %@", error, [error userInfo]);
abort();
}
// Step 2: Update Object
SystemParameters *systemParameters = [items objectAtIndex:0];
////
// GPS SIMULATOR
////
[systemParameters setMGpsSimulatorEnabled:[theSystemParameters mGpsSimulatorEnabled]];
[systemParameters setMGpsSimulatorFileName:[theSystemParameters mGpsSimulatorFileName]];
[systemParameters setMGpsSimulatorPlaybackSpeed:[theSystemParameters mGpsSimulatorPlaybackSpeed]];
// Step 3: Save Updates
[self saveAction];
}
As to can see, I fetch the object that I want to update, change its values and save. Here is the saving code:
- (void)saveAction {
NSError *error;
if (![[self mManagedObjectContext] save:&error]) {
NSLog(@"ERROR:saveAction. Unresolved Core Data Save error %@, %@", error, [error userInfo]);
exit(-1);
}
}
The Persistent store method:
- (NSPersistentStoreCoordinator *)persistentStoreCoordinator {
if (mPersistentStoreCoordinator != nil) {
return mPersistentStoreCoordinator;
}
NSString *path = [self databasePath];
NSURL *storeUrl = [NSURL fileURLWithPath:path];
NSError *error = nil;
mPersistentStoreCoordinator = [[NSPersistentStoreCoordinator alloc] initWithManagedObjectModel:[self managedObjectModel]];
if (![mPersistentStoreCoordinator addPersistentStoreWithType:NSSQLiteStoreType configuration:nil URL:storeUrl options:nil error:&error]) {
NSLog(@"Unresolved error %@, %@", error, [error userInfo]);
abort();
}
return mPersistentStoreCoordinator;
}
The managed object class definition:
#import <Foundation/Foundation.h>
typedef enum {
UISwitchParameterIdGpsSimulatorEnable,
UISwitchParameterIdIllegal
}UISwitchParameterId;
@interface SystemParameters : NSManagedObject {
// NSManagedObjectContext *mManagedObjectContext;
////
// GPS SIMULATOR
////
BOOL mGpsSimulatorEnabled;
NSString *mGpsSimulatorFileName;
NSInteger mGpsSimulatorPlaybackSpeed;
}
@property (nonatomic, assign) BOOL mGpsSimulatorEnabled;
@property (nonatomic, retain) NSString *mGpsSimulatorFileName;
@property (nonatomic, assign) NSInteger mGpsSimulatorPlaybackSpeed;
+ (SystemParameters *)sharedInstance;
- (void) saveToCoreData;
@end
There is no error but the sqLite file is not updated, hence the data is not persistent.
Thanks in advance.
I had a very similar problem a few months back. I couldn't get my sql store to update when running on the simulator.
Turned out, I was looking in the wrong application folder for the simulator. If you restart the simulator or the CPU it sometimes creates an entirely new directory for the app. I kept looking at the original application folder when all the changes I had made where being written to the new one.
If that's not the problem, I would look at the definition of the SystemParameters
class and see if there could be a fault there. A bad custom accessor or faulty validation code can cause objects not to save data without generating an error.
Edit
You SystemParameters
class is very odd. I don't think it will work.
First of all, you seem to have it defined as a singleton. Core Data doesn't recognize singletons for its entities. I'm not sure how that will work out if it will work at all.
Second, your property definitions for you scalars are incorrect. Core Data only stores objects so BOOL attributes and integer attributes have to converted to NSNumber instances. Your properties should look like:
@property (nonatomic, retain) NSNumber *mGpsSimulatorEnabled;
@property (nonatomic, retain) NSString *mGpsSimulatorFileName;
@property (nonatomic, retain) NSNumber *mGpsSimulatorPlaybackSpeed;
I recommend that you let Xcode generate the managed object subclasses for you based on the entity graph. That way, you'll get the right types and the correct handling automatically.
As an aside, this:
SystemParameters *systemParametersEntity = (SystemParameters *)[NSEntityDescription insertNewObjectForEntityForName:@"SystemParameters" inManagedObjectContext:mManagedObjectContext];
Is an unnecessary cast. -[NSEntityDescription -insertNewObjectForEntityName: inManagedObjectContext]
returns an id which is a generic pointer.
SystemParameters *systemParametersEntity = [NSEntityDescription insertNewObjectForEntityForName:@"SystemParameters" inManagedObjectContext:mManagedObjectContext];
Is correct. 99% of the time, if you are casting in Objective-C you are probably doing it wrong.
Replace your persistentStoreCoordinator method with this code and try
- (NSPersistentStoreCoordinator *)persistentStoreCoordinator {
if (persistentStoreCoordinator != nil) {
return persistentStoreCoordinator;
}
NSString *storePath = [[self applicationDocumentsDirectory] stringByAppendingPathComponent:@"projectname.sqlite"];
/*
Set up the store.
For the sake of illustration, provide a pre-populated default store.
*/
NSFileManager *fileManager = [NSFileManager defaultManager];
// If the expected store doesn't exist, copy the default store.
if (![fileManager fileExistsAtPath:storePath]) {
NSString *defaultStorePath = [[NSBundle mainBundle] pathForResource:@"projectname" ofType:@"sqlite"];
if (defaultStorePath) {
[fileManager copyItemAtPath:defaultStorePath toPath:storePath error:NULL];
}
}
NSURL *storeUrl = [NSURL fileURLWithPath:storePath];
NSError *error;
persistentStoreCoordinator = [[NSPersistentStoreCoordinator alloc] initWithManagedObjectModel: [self managedObjectModel]];
if (![persistentStoreCoordinator addPersistentStoreWithType:NSSQLiteStoreType configuration:nil URL:storeUrl options:nil error:&error]) {
/*
Replace this implementation with code to handle the error appropriately.
abort() causes the application to generate a crash log and terminate. You should not use this function in a shipping application, although it may be useful during development. If it is not possible to recover from the error, display an alert panel that instructs the user to quit the application by pressing the Home button.
Typical reasons for an error here include:
* The persistent store is not accessible
* The schema for the persistent store is incompatible with current managed object model
Check the error message to determine what the actual problem was.
*/
NSLog(@"Unresolved error %@, %@", error, [error userInfo]);
abort();
}
return persistentStoreCoordinator;
}
projectname can be replaced with your project name.
I too had the same problem, i changed my persistentStoreCoordinator method.It worked fine.
All the best.
精彩评论