【问题标题】:Passing NSManagedObject传递 NSManagedObject
【发布时间】:2013-10-04 17:46:46
【问题描述】:

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

我编写了一个方法,它为我定期发出的特定获取请求返回一个 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 编写干净的访问器方法?

【问题讨论】:

    标签: ios objective-c model-view-controller nsmanagedobject nsmanagedobjectid


    【解决方案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;
    }
    

    还可以查看this post 了解更多场景和解决方案。

    编辑:

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

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

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

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

    【讨论】:

    • 那篇文章正是我的堆栈设置方式。谢谢。这是否可行,因为与传递 NSManagedObject 相关的线程问题与 NSManagedObjectContexts 直接相关?
    • 请看我的编辑。我试图澄清应该如何使用该方法。
    • 实施这个策略后,通常会返回 nil 而不是 NSManagedObject。我以前的实现不是这样的。关于为什么我得到 nil 的任何想法? (如果需要,我可以提出一个新问题,但它与此答案直接相关)。
    • 很奇怪...我对此没有任何解释。首先,我会传入一个 NSError 对象并在查询后查看它包含的内容;然后,我将为该方法设置一个单元测试,您只需为存储的所有 id 重复调用它,看看会发生什么。知道在什么情况下获取失败会很有趣......
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2015-11-26
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多