Ios 保存:在NSManagedObjectContext上不工作

Ios 保存:在NSManagedObjectContext上不工作,ios,core-data,Ios,Core Data,在导航控制器中,我从视图控制器1转到视图控制器2 视图控制器1是绑定到FetchedResultsController的表视图控制器。它从特定上下文中获取数据并显示它。然后,如果点击一行,我将继续查看控制器2。在分段时,我使用视图控制器1中的数据设置视图控制器2的特定NSManagedObject属性 现在,在view controller 2中,我可以使用NSManagedObject属性显示数据,然后对其进行更改并执行保存:。当我返回视图控制器1时,将反映更改。但是,如果我重新启动应用程序,

在导航控制器中,我从视图控制器1转到视图控制器2

视图控制器1是绑定到FetchedResultsController的表视图控制器。它从特定上下文中获取数据并显示它。然后,如果点击一行,我将继续查看控制器2。在分段时,我使用视图控制器1中的数据设置视图控制器2的特定NSManagedObject属性

现在,在view controller 2中,我可以使用NSManagedObject属性显示数据,然后对其进行更改并执行保存:。当我返回视图控制器1时,将反映更改。但是,如果我重新启动应用程序,它将不再反映在任何视图控制器中

我就是这样做的

- (void)hiddenAttributeSwitchSlid:(UISwitch *)sender
{
    [self.workoutType.managedObjectContext performBlock:^{
        self.workoutType.workoutHiddenByDefault = [NSNumber numberWithBool:sender.isOn];
        NSError *error = nil;
        if (![self.workoutType.managedObjectContext save:&error]) {
            NSLog(@"There was an error in saving to context - %@", [error localizedDescription]);
        }
        else {
            NSLog(@"No error");
        }
    }];
}
workoutType是一个NSManagedObject,在切换到此视图控制器之前在prepareForSegue:中设置

即使我不使用performBlock:,它也不起作用


我知道以前有人问过这种问题。我浏览了一遍,但似乎没有任何效果

您的模型中是否为该属性设置了默认值

在核心数据中存在一个已识别的bug,在某些情况下(我没有将其缩小),具有默认值的属性会在应用程序的后台处理过程中多次重置

对此进行测试的方法是,通过KVO侦听正在更改的值,并记录更改,然后复制测试。如果您看到一些更改,那么您就知道您遇到了该错误

我所看到的唯一可靠的已知解决方案是删除默认值。如果需要默认值,我会将其添加到
-awakeFromInsert
方法中的
NSManagedObject
子类中,然后更新验证方法以检查它。我知道这很糟糕

更新#2 你有多少上下文

您是否使用父子上下文

如果是,您是否正在保存最顶层的父级

更新#3 好的,
UIManagedDocument
中有两个
NSManagedObjectContext
实例。是否有使用
UIManagedDocument
的原因?您的申请中是否有多个文档?如果您不这样做,我强烈建议您切换回传统的核心数据堆栈。
UIManagedDocument
实际上并不是要放在单堆栈应用程序中

对于直接保存问题,
UIManagedDocument
在退出应用程序时尝试在后台保存。如果可能需要一点时间,就个人而言,不是很可靠。您可以在退出时请求保存,这将有助于确保保存速度,但即使如此,也可能不可靠

如何退出应用程序

你是在用Xcode杀死它吗

你是将其背景化,然后恢复它吗

你是否将其备份,然后从iOS设备上删除它


您可以侦听要保存的
UIManagedDocument
,然后打印一条日志语句,这样您就可以看到磁盘何时实际发生了保存。这可能有助于准确缩小保存和不保存的时间范围。

您的模型中是否为该属性设置了默认值

在核心数据中存在一个已识别的bug,在某些情况下(我没有将其缩小),具有默认值的属性会在应用程序的后台处理过程中多次重置

对此进行测试的方法是,通过KVO侦听正在更改的值,并记录更改,然后复制测试。如果您看到一些更改,那么您就知道您遇到了该错误

我所看到的唯一可靠的已知解决方案是删除默认值。如果需要默认值,我会将其添加到
-awakeFromInsert
方法中的
NSManagedObject
子类中,然后更新验证方法以检查它。我知道这很糟糕

更新#2 你有多少上下文

您是否使用父子上下文

如果是,您是否正在保存最顶层的父级

更新#3 好的,
UIManagedDocument
中有两个
NSManagedObjectContext
实例。是否有使用
UIManagedDocument
的原因?您的申请中是否有多个文档?如果您不这样做,我强烈建议您切换回传统的核心数据堆栈。
UIManagedDocument
实际上并不是要放在单堆栈应用程序中

对于直接保存问题,
UIManagedDocument
在退出应用程序时尝试在后台保存。如果可能需要一点时间,就个人而言,不是很可靠。您可以在退出时请求保存,这将有助于确保保存速度,但即使如此,也可能不可靠

如何退出应用程序

你是在用Xcode杀死它吗

你是将其背景化,然后恢复它吗

你是否将其备份,然后从iOS设备上删除它


您可以侦听要保存的
UIManagedDocument
,然后打印一条日志语句,这样您就可以看到磁盘何时实际发生了保存。这可能有助于准确地缩小保存时间和不保存时间。

来自UIManageDocument文档:

UIManagedDocument体系结构需要考虑以下几点:

通常应使用标准UIDocument方法保存文档。 如果直接保存子上下文,则只将更改提交到父上下文,而不提交到文档存储。如果直接保存父上下文,则可以避开文档执行的其他重要操作


最简单的选择是使用无保存模型,这意味着使用文档的NSUndoManager。我通常在添加更改之前和编辑之后执行此操作。

来自UIManageDocument文档
[self.workoutType.managedObjectContext.undoManager beginUndoGrouping];
[self.workoutType.managedObjectContext.undoManager endUndoGrouping];
@interface LoggingManagedDocument : UIManagedDocument

@end
#import "LoggingManagedDocument.h"

@implementation LoggingManagedDocument

- (id)contentsForType:(NSString *)typeName error:(NSError *__autoreleasing *)outError
{
    NSLog(@"Auto-Saving Document");
    return [super contentsForType:typeName error:outError];
}

- (void)handleError:(NSError *)error userInteractionPermitted:(BOOL)userInteractionPermitted
{
    NSLog(@"error: %@ userInfo: %@", error, error.userInfo);
}

@end
[document saveToURL:document.fileURL forSaveOperation:UIDocumentSaveForOverwriting completionHandler:NULL];