如何在块之间访问NSManagedObjects?

时间:2015-04-26 05:30:24

标签: ios core-data nsmanagedobject nsmanagedobjectcontext magicalrecord

与标题一样,如何访问已在一个块中创建的NSManagedObject,然后需要在另一个块中访问。我有以下实现,并想知道它是否正确。

__block Person *newPerson;

@weakify(self);
[MagicalRecord saveWithBlock:^(NSManagedObjectContext *localContext) {

    newPerson = [Person MR_createInContext:localContext];
    newPerson.name = @"Bob";

} completion:^(BOOL success, NSError *error) {
    @strongify(self);
    // Called on main thread

    PersonViewController *personVC = [[PersonViewController alloc] initWithPerson:newPerson];
    [self.navigationController pushViewController:personVC animated:YES];

}];

我是否正确无需从完成处理程序中的localContext访问newPerson,因为它将在主线程上执行?

修改

看起来以下是建议的方式:

__block NSManagedObjectID *newPersonObjectID;

@weakify(self);
[MagicalRecord saveWithBlock:^(NSManagedObjectContext *localContext) {

    Person *newPerson = [Person MR_createInContext:localContext];
    newPerson.name = @"Bob";
    newPersonObjectID = newPerson.objectID;

} completion:^(BOOL success, NSError *error) {
    @strongify(self);
    // Called on main thread

    Person *savedPerson = [[NSManagedObjectContext MR_defaultContext] objectWithID:newPersonObjectID];

    PersonViewController *personVC = [[PersonViewController alloc] initWithPerson:savedPerson];
    [self.navigationController pushViewController:personVC animated:YES];

}];

解决方案

这个答案和评论导致以下解决方案。 临时ID正在被保存时被分配给对象,因此当尝试使用TempID获取对象时,会发生异常。

不是创建一个全新的获取请求,而是要求上下文尽早获取永久ID,而不是获取对象的永久ID。例如:

__block NSManagedObjectID *newPersonObjectID;

@weakify(self);
[MagicalRecord saveWithBlock:^(NSManagedObjectContext *localContext) {

    Person *newPerson = [Person MR_createInContext:localContext];
    newPerson.name = @"Bob";

    [localContext obtainPermanentIDsForObjects:@[newPerson] error:NULL];

    newPersonObjectID = newPerson.objectID;

} completion:^(BOOL success, NSError *error) {
    @strongify(self);
    // Called on main thread

    Person *savedPerson = [[NSManagedObjectContext MR_defaultContext] objectWithID:newPersonObjectID];

    PersonViewController *personVC = [[PersonViewController alloc] initWithPerson:savedPerson];
    [self.navigationController pushViewController:personVC animated:YES];

}];

2 个答案:

答案 0 :(得分:2)

您无法在上下文之间直接传递托管对象。每个NSManagedObject只能通过自己的上下文访问。

您需要将其objectID传递给完成块,然后让主上下文通过调用以下方法之一来获取对象:

-(NSManagedObject *)objectWithID:(NSManagedObjectID *)objectID

这将为具有指定objectID的对象创建一个错误,无论它是否实际存在于商店中。如果它不存在,那么触发故障的任何事情都将失败并出现异常。

-(NSManagedObject *)existingObjectWithID:(NSManagedObjectID *)objectID
                                   error:(NSError **)error

这将从具有该ID的商店中获取对象,或者如果它不存在则返回nil。与objectWithID不同,该对象不会出现故障;将检索其所有属性。

在任何一种情况下,您的本地上下文必须已将Person对象保存到商店,以便主要上下文能够获取它。

有关objectID的更多详细信息,请参阅Core Data Programming Guide

按用户提问提问

这个答案和评论会导致正确的解决方案。 临时ID正在被保存时被分配给对象,因此在尝试使用TempID获取对象时会发生异常。

不是创建一个全新的获取请求,而是要求上下文尽早获取永久ID,而不是获取对象的永久ID。例如:

__block NSManagedObjectID *newPersonObjectID;

@weakify(self);
[MagicalRecord saveWithBlock:^(NSManagedObjectContext *localContext) {

    Person *newPerson = [Person MR_createInContext:localContext];
    newPerson.name = @"Bob";

    [localContext obtainPermanentIDsForObjects:@[newPerson] error:NULL];

    newPersonObjectID = newPerson.objectID;

} completion:^(BOOL success, NSError *error) {
    @strongify(self);
    // Called on main thread

    Person *savedPerson = [[NSManagedObjectContext MR_defaultContext] objectWithID:newPersonObjectID];

    PersonViewController *personVC = [[PersonViewController alloc] initWithPerson:savedPerson];
    [self.navigationController pushViewController:personVC animated:YES];

}];

答案 1 :(得分:1)

您应该访问块外部的objectID(例如,在主线程上),然后在块中使用它。类似的东西:

NSManagedObjectID *objectID = appDelegate.myObject.objectId;
dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_BACKGROUND, 0), ^{
    // use objectID here.
}