NSManagedObject保持错误

时间:2013-02-06 21:02:27

标签: ios core-data

我的情况: 假设我有一个类Person(NSManagedObject的子类)。每次用户单击按钮时,都会创建一个新的Person实例并将其添加到全局NSMutableArray中。此外,新创建的Person实例将添加到子上下文中,如下所示:

NSManagedObjectContext *childContext = [[NSManagedObjectContext alloc] initWithConcurrencyType: NSPrivateConcurrencyType];
[childContext setParentContext: _mainContext];

同样在点击按钮时我保存了上下文:(它有点复杂,但遵循这个结构)

[childContext performBlock:^{
    [childContext save:nil];
    [_mainContext save:nil];
}];

点击两次或多次(不确定是否取决于总点击次数)后,我的数组中的按钮对象变为fault

根据文档:访问故障对象的属性应该加载持久对象 即使我访问NSManagedObject的属性,对象仍然是错误的,属性是nil

为什么对象在我的数组中出错?如何访问故障对象的属性?

修改

加载UIViewController时,我从数据存储区中获取所有现有对象:

-(NSArray*)fetchPersons {
    NSManagedObjectContext *context = [self managedObjectContext]; //this is _mainContext, it is created with initWithConcurrencyType:NSMainQueueConcurrencyType
    NSFetchRequest  *fetchRequest = [[NSFetchRequest alloc] init];
    NSEntityDescription *description = [NSEntityDescription entityForName:@"Person" inManagedObjectContext:context];
    [fetchRequest setEntity:description];
    NSPredicate *predicate = [NSPredicate predicateWithFormat:@"key = %i", aCondition];
    [fetchRequest setPredicate:predicate];
    return [context executeFetchRequest:fetchRequest error:nil];
}

我正在使用fetchPersons中的NSArray来填充NSMutableArray。

创建一个新的Person对象:

-(Person*)createPerson {
    NSManagedObjectContext *childContext = [[NSManagedObjectContext alloc] initWithConcurrencyType: NSPrivateQueueConcurrencyType]; 
    [childContext setParentContext:[self managedObjectContext]];
    Person *person = [NSEntityDescription insertNewObjectForEntityForName:@"Person" inManagedObjectContext:childContext];
    return person;
} 

我不确定如何使用òbjectID`处理对象。 我正在使用childContext作为临时上下文。有时我需要一个Person实例,但我不想将它保存到持久性存储中(或者在开头将其插入主上下文中)。

完成所有这些步骤后,我的NSMutableArray中包含了所有对象。在创建一些对象并尝试记录它们的属性(person.name或其他东西)后,我得到了nil属性(fault对象)。

1 个答案:

答案 0 :(得分:18)

NSManagedObject与创建它们的NSManagedObjectContext保持紧密关系。具体原因是托管对象总是可变的,因此可能需要回写到商店,并且期望未来的错误 - 核心数据显然可以选择不将整个持久性存储加载到内存中但可能必须处理您将来对对象图的任意遍历或低记忆警告。

(除此之外:这也是核心数据对象无法用于创建它们的线程/队列以外的任何其他内容的最直接原因;它是上下文和上下文与对象之间隐式通信的各个部分这是不安全的)

在实践中,这意味着您不应该允许托管对象超过其商店。

为了允许您在具有不同上下文的不同代理之间来回发送对象,Apple实现了NSManagedObjectID,它是任何托管对象的唯一标识符。它是一个完全不透明的类,但是,作为信息,如果你有一个SQLite存储,那么它是对相关表和行的引用;如果你有其他商店类型之一,那么它同样是指向商店中某个位置的指针。它本身不携带任何对象数据。

所以你通常做的是在对象上调用objectID,而在它下面创建的上下文仍然存在。然后,您可以将其传递给其他人想要它。然后,他们将使用[myManagedObjectContext -existingObjectWithID:error:]获取可以安全使用的托管对象的新副本。新副本将绑定到该上下文而不是原始副本,因此无论何时且无论多长时间上下文都是安全的,都是安全的,而不是原始文件。

唯一可能的惊喜是,当您第一次插入对象时,它只获得一个临时对象ID。这是因为Core Data喜欢批量处理需要插入商店的内容,然后只在您请求保存时才将它们全部插入。

出于您的目的,您不希望直到保存之后才传递ID,因为该对象将不存在于父存储中。所以这一点部分是学术性的,但假设你想要因为其他原因而忽略了ID,你可能还会考虑使用上下文-obtainPermanentIDsForObjects:error:,这可能比实际保存要快得多,具体取决于你的商店类型,肯定永远不会慢。