我正在更新iOS 7的现有应用程序,我一直遇到Core Data保存对象的一些问题。这是一个相当简单的主 - 细节风格数据输入应用程序,它使用Core Data进行存储。
添加新记录时,我使用第二个(临时)托管对象上下文来防止记录在保存记录之前出现在列表中。添加并保存记录后,它将按预期显示在列表中。但是,如果我退出应用程序(它不在后台运行)然后重新启动它,则记录不再存在。该记录存在于数据库中(无论如何都使用SQLite Manager Firefox插件可见),但它不会在应用程序中显示。
我已经设法使用Xcode在创建新项目时生成的代码重现了这一点。我已经创建了一个新的主 - 详细信息应用程序,并勾选了使用核心数据框以获取示例代码,然后进行了以下更改:
将以下内容添加到MasterViewController.m
-(void)save:(NSManagedObjectContext*)context
{
if (context != [self.fetchedResultsController managedObjectContext])
{
NSNotificationCenter *dnc = [NSNotificationCenter defaultCenter];
[dnc addObserver:self selector:@selector(addControllerContextDidSave:) name:NSManagedObjectContextDidSaveNotification object:context];
}
NSError *error;
if (![context save:&error])
{
abort();
}
if (context != [self.fetchedResultsController managedObjectContext])
{
NSNotificationCenter *dnc = [NSNotificationCenter defaultCenter];
[dnc removeObserver:self name:NSManagedObjectContextDidSaveNotification object:context];
}
}
- (void)addControllerContextDidSave:(NSNotification*)saveNotification
{
[[self.fetchedResultsController managedObjectContext] mergeChangesFromContextDidSaveNotification:saveNotification];
}
使用以下内容替换insertNewObject中提供的insertNewObject
以创建用于添加的新临时上下文
- (void)insertNewObject:(id)sender
{
NSManagedObjectContext *context = [[NSManagedObjectContext alloc] init];
context.persistentStoreCoordinator = [[self.fetchedResultsController managedObjectContext] persistentStoreCoordinator];
NSEntityDescription *entity = [[self.fetchedResultsController fetchRequest] entity];
NSManagedObject *newManagedObject = [NSEntityDescription insertNewObjectForEntityForName:[entity name] inManagedObjectContext:context];
// If appropriate, configure the new managed object.
// Normally you should use accessor methods, but using KVC here avoids the need to add a custom class to the template.
[newManagedObject setValue:[NSDate date] forKey:@"timeStamp"];
// Save the context.
[self save:context];
}
我还将应用设置为不在后台运行。
如果我针对iOS 6运行它,它的行为符合预期,即我点击添加并显示新记录,然后退出并重新启动应用程序并且记录仍然存在。
但是,如果我针对iOS 7运行相同的代码,则无法正常运行。点击添加会导致出现新记录,但如果我退出并重新启动应用程序,则不显示记录。如上所述,它存在于数据库中。
有趣的是,我发现它可能在某种程度上与SQLite数据库的日记模式的变化有关。如果我在调用addPersistentStoreWithType
时添加以下选项,我会在iOS 7上运行预期的行为
NSDictionary *options = @{ NSSQLitePragmasOption : @{@"journal_mode" : @"DELETE"} };
所以,问题(感谢你们阅读这篇文章!)
干杯
尼尔
编辑1:
在回答Wain关于保存主要MOC的问题时,我认为这实际上并不是必需的,因为数据已经保存,合并只是将已保存的更改从临时上下文更新到主上下文。也就是说测试代码确实包含以下方法,并在关闭时调用saveContext
,但[managedObjectContext hasChanges]
返回false,因此此时实际上没有完成
-(void)applicationWillTerminate:(UIApplication *)application
{
// Saves changes in the application's managed object context before the application terminates.
[self saveContext];
}
-(void)saveContext
{
NSError *error = nil;
NSManagedObjectContext *managedObjectContext = self.managedObjectContext;
if (managedObjectContext != nil)
{
if ([managedObjectContext hasChanges])
{
if (![managedObjectContext save:&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.
NSLog(@"Unresolved error %@, %@", error, [error userInfo]);
abort();
}
}
}
}
答案 0 :(得分:0)
在合并更改后保存主要上下文时似乎已修复:
- (void)addControllerContextDidSave:(NSNotification*)saveNotification
{
[[self.fetchedResultsController managedObjectContext] mergeChangesFromContextDidSaveNotification:saveNotification];
[self save:[self.fetchedResultsController managedObjectContext]];
}
更新:此错误是由NSFetchedResultsController
中的缓存引起的。因此,数据不会丢失,只是您的NSFetchedResultsController
无法显示。需要进一步调查,以找出缓存在MOC合并更改时未更新的原因,但未保存。