0

我正在将一些代码从我的控制器移动到核心数据应用程序中的模型。

我编写了一个方法,该方法为我定期发出的特定获取请求返回一个 NSManagedObjectID。

+ (NSManagedObjectID*)teamProjectWithProjectId:(NSNumber *)projectId inContext:(NSManagedObjectContext*)context
{
    NSFetchRequest *teamRequest = [[NSFetchRequest alloc] initWithEntityName:@"TeamProject"];
    NSPredicate *teamPredicate = [NSPredicate predicateWithFormat:@"teamProjectId == %@",projectId];
    teamRequest.predicate = teamPredicate;
    TeamProject *teamProject = [[context executeFetchRequest:teamRequest error:nil] lastObject];
    if (teamProject)
    {
      return [teamProject objectID];
    }
    else
    {
      return nil;
    }
    return nil;
}

现在在任何地方我都需要使用我这样做的方法:

NSManagedObjectID *teamProjectMoId = [TeamProject teamProjectWithProjectId:projectID];
TeamProject *currentProject = nil;
if (teamProjectMoId)
{
    currentProject = (TeamProject*)[self.managedObjectContext objectWithID:teamProjectMoId];
}

现在这还不错,它可以工作并且它尊重 NSManagedObject 不是线程安全的,而 NSManagedObjectID 是线程安全的。我很高兴能够将相当多的代码从我的控制器类移到我的模型类别中。

然而,这还不够好。我真的很想以尊重线程安全的方式只用一行代码访问一个 NSManagedObject。我的理想是能够写出这样的东西:

TeamProject *currentProject = [TeamProject magicalMethodThatHandlesThreadSafety];

这甚至可能吗?或者有没有人有任何策略来为 NSManagedObject 编写干净的访问器方法?

4

1 回答 1

1

您可以在需要在后台进行查找的任何地方创建一个临时 MOC。这当然是线程安全的,并且比使用 ID 更快(实际上,它很快,因为创建 MOC 本身很快)。

一种方法是通过一个子项到您的主要上下文中指定NSPrivateQueueConcurrencyType并发类型:

+ (TeamProject*)teamProjectWithProjectId:(NSNumber *)projectId inContext:(NSManagedObjectContext*)context
{

    NSManagedObjectContext *temporaryContext = [[NSManagedObjectContext alloc] initWithConcurrencyType:NSPrivateQueueConcurrencyType];
    temporaryContext.parentContext = context;

    NSFetchRequest *teamRequest = [[NSFetchRequest alloc] initWithEntityName:@"TeamProject"];
    NSPredicate *teamPredicate = [NSPredicate predicateWithFormat:@"teamProjectId == %@",projectId];
    teamRequest.predicate = teamPredicate;
    TeamProject *teamProject = [[temporaryContext executeFetchRequest:teamRequest error:nil] lastObject];

    return teamProject;
}

还可以查看这篇文章以了解更多场景和解决方案。

编辑:

为了让事情更清楚,上面的方法是从使用返回 MO 的同一个线程调用的。它只是上述方法的“扩展”,因为它使用本地创建的 MOC 包装获取操作,该 MOC 是该线程私有的,因此您可以安全地使用它。

换句话说,您可以从任何线程调用上述方法,并在同一个线程中安全地使用返回的 MO。使用子 MOC 的技巧允许您通过创建临时私有 MOC 在任何线程中进行提取。

引用在另一个线程中创建的 MOC 以在当前线程中创建子 MOC 是安全的。

仍然不允许将托管对象从一个线程传递到另一个线程。

于 2013-10-04T17:52:00.007 回答