Iphone iOS7上具有多个NSManagedObjectContext的数据丢失
我正在为iOS 7更新一个现有应用程序,我在核心数据保存对象方面遇到了一些问题。它是一款非常简单的主-细节式数据输入应用程序,使用核心数据进行存储 添加新记录时,我使用第二个(临时)托管对象上下文来防止记录在保存前出现在列表中。添加并保存记录后,它将按预期显示在列表中。但是,如果我退出应用程序(它不会在后台运行),然后重新启动它,记录将不再存在。该记录存在于数据库中(无论如何使用SQLite Manager Firefox插件都可以看到),但它不会显示在应用程序中 我使用Xcode在创建新项目时生成的代码成功地重现了这一点。我已经创建了一个新的master detail应用程序,并勾选Use Core Data框以获取示例代码,然后进行了以下更改:Iphone iOS7上具有多个NSManagedObjectContext的数据丢失,iphone,ios,objective-c,sqlite,core-data,Iphone,Ios,Objective C,Sqlite,Core Data,我正在为iOS 7更新一个现有应用程序,我在核心数据保存对象方面遇到了一些问题。它是一款非常简单的主-细节式数据输入应用程序,使用核心数据进行存储 添加新记录时,我使用第二个(临时)托管对象上下文来防止记录在保存前出现在列表中。添加并保存记录后,它将按预期显示在列表中。但是,如果我退出应用程序(它不会在后台运行),然后重新启动它,记录将不再存在。该记录存在于数据库中(无论如何使用SQLite Manager Firefox插件都可以看到),但它不会显示在应用程序中 我使用Xcode在创建新项目时
- (void)addControllerContextDidSave:(NSNotification*)saveNotification
{
[[self.fetchedResultsController managedObjectContext] mergeChangesFromContextDidSaveNotification:saveNotification];
[self save:[self.fetchedResultsController managedObjectContext]];
}
将以下内容添加到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上运行此应用程序,它的行为与预期一致,即我点击Add并显示一条新记录,然后退出并重新启动应用程序,该记录仍然存在
但是,如果我在iOS7上运行相同的代码,它就不能正常工作。点击Add会显示新记录,但如果我退出并重新启动应用程序,则不会显示该记录。如上所述,它存在于数据库中
有趣的是,我发现它可能在某种程度上与SQLite数据库日志记录模式的改变有关。如果我在调用addPersistentStoreWithType
中添加以下选项,我将获得在iOS 7上运行的预期行为
NSDictionary *options = @{ NSSQLitePragmasOption : @{@"journal_mode" : @"DELETE"} };
所以,对于这些问题(感谢您阅读到这里!)
- 是否有其他人见过这种行为(或者有人能够根据上述描述重现这种行为)
- 在iOS 7之前,我只是幸运地使用了一个临时上下文,我使用的方式是否有问题,或者这看起来像是iOS 7上的核心数据框架的问题
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();
}
}
}
}
在合并更改后保存主上下文时,它似乎是固定的:
- (void)addControllerContextDidSave:(NSNotification*)saveNotification
{
[[self.fetchedResultsController managedObjectContext] mergeChangesFromContextDidSaveNotification:saveNotification];
[self save:[self.fetchedResultsController managedObjectContext]];
}
更新:此错误是由于在
NSFetchedResultsController
中使用缓存造成的。因此,数据并没有丢失,只是您的NSFetchedResultsController不显示它。需要进一步调查,以找出为什么缓存在其MOC合并更改时没有更新,但没有保存。为什么不在获取请求中使用includesPendingChanges
?@Wain-我想这可能是一种可能性(我不确定为什么没有更新,可能在编写原始代码时没有意识到该参数)但我真的很想了解为什么我的应用程序在你如何(或者更确切地说,何时)保存持久性上下文方面能像预期的那样工作?@Wain-我已经添加到原始帖子中,我认为它应该按照你的方式工作(检查添加后磁盘上的文件是否更新)。将journal_mode
设置为DELETE
基本上重置为iOS 7之前的值。考虑用你的采样项目来提升雷达。有趣的是,这似乎解决了这个问题。我很想知道你是否知道为什么会这样,因为我认为没有必要这样做,而且奇怪的是,当使用不同的日志类型时,行为会发生变化。谢谢Arkadiusz。我已经向苹果公司提交了一份bug报告:15161551