我正在为 iOS 7 更新现有应用程序,并且在保存核心数据对象方面遇到了一些问题。这是一个相当简单的主从样式数据输入应用程序,使用 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"} };
所以,对于问题(感谢您阅读本文!)
- 有没有其他人看到过这种行为(或者是否有人能够根据上面的描述重现它)?
- 我在使用 iOS 7 之前幸运的临时上下文的方式是否有问题,或者这看起来像是 iOS 7 上的 Core Data 框架的问题?
干杯
尼尔
编辑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();
}
}
}
}