【问题标题】:What is the new way of binding an NSArrayController to the managed object context of a Core Data document?将 NSArrayController 绑定到 Core Data 文档的托管对象上下文的新方法是什么?
【发布时间】:2015-03-26 21:05:20
【问题描述】:

在 Xcode 为 OS X 应用程序添加 Storyboards 之前,您可以通过将数组控制器的 Managed Object Context 绑定到 File's OwnerModel Key PathmanagedObjectContext 来将数组控制器连接到文档的托管对象上下文。有了故事板,就不再有 File's Owner 了,那么你从哪里获得上下文?

Apple 的文档在这方面落后,在 Xcode 中没有任何明显的地方可以绑定。显然我可以退回到非故事板路线并使用旧方法,但必须有一种新方法。

【问题讨论】:

    标签: xcode core-data interface-builder cocoa-bindings


    【解决方案1】:

    所以我从 Apple 那里得到了答案。这是针对基于文档的核心数据应用程序,代码全部在 Swift 中,但在 Objective-C 中的想法是相同的,您只需翻译它。

    他们给我的第一个答案是将数组控制器绑定到运行视图的视图控制器,模型键路径为self.view.window.windowController.document.managedObjectContex。我看到的示例使用了这种方法并且根本没有错误消息,但是它是窗口控制器内的一个视图控制器,带有一个数组控制器。我的设置是一个选项卡视图的窗口,在一个场景中具有两个数组控制器的视图。每次打开或创建新文档时,我仍然会收到一次Cannot perform operation without a managed object context。对我有用的第二个解决方案仍然是将数组控制器绑定到视图控制器,但模型键路径为 self.representedObject.managedObjectContext,然后添加到文档类的 makeWindowControllers() 函数的末尾:

    override func makeWindowControllers() {
    ……
        let tabViewController = windowController.contentViewController as NSTabViewController
        for object in tabViewController.childViewControllers {
            let childViewController = object as NSViewController
            childViewController.representedObject = self
        }
    }
    

    这为我解决了这个问题。希望这里有足够的信息可以在其他人用 Google 搜索此问题时显示出来。

    【讨论】:

    • 我的问题是在 let windowController = storyboard.instantiateControllerWithIdentifier("Document Window Controller") as 期间要求故事板视图控制器中对象控制器的 managedObjectContext ! NSWindowController 在我有机会将代表对象设置为文档之前调用。
    【解决方案2】:

    使用默认的 Xcode 生成项目并包含 CoreData 会将 managedObjectContext 成员放在 AppDelegate 上。您可以将以下代码添加到您的 ViewController,然后使用 managedObjectContext 作为“模型密钥路径”,并为您的 NSArrayController 绑定到 ViewController

    lazy var managedObjectContext: NSManagedObjectContext = { 
        return (NSApplication.sharedApplication().delegate
            as? AppDelegate)?.managedObjectContext }()!
    

    这只是创建一个重定向到实际 MOC 存储位置的成员。这很有用,因为 NSArrayController 绑定发生在 viewDidLoad() 之前,因此实例成员不够用。此外,如果您想重构为单例 CoreDataManager 类,您只需更改重定向到的位置即可。此外,您可以将其添加为类扩展,以使所有 ViewControllers 都能访问您的 MOC。

    根据要求提供 Objective-C 版本:

    @interface MyViewController ()
    
    @property (nonatomic, readonly) NSMangedObjectContext* managedObjectContext;
    
    @end
    
    @implementation MyViewController
    
    - (NSManagedObjectContext*)managedObjectContext
    {
        return ((AppDelegate*)([NSApplication sharedApplication].delegate)).managedObjectContext;
    }
    
    ...
    
    @end
    

    【讨论】:

    • @Chapman: 你能把你的例子翻译成客观 c
    • @user3175421 :更新为 Obj-C 版本。不太简洁;)
    • 没有那么简洁,但可读性更强!或者用其他标点符号:return [(AppDelegate *)[[NSApplication sharedApplication] delegate] managedObjectContext];
    【解决方案3】:

    如果应用程序委托拥有核心数据堆栈,则您始终能够通过 NSApplication 与 delegate.managedObjectContext 的键路径进行绑定。否则,您可以将 MOC 传递给每个视图控制器,每个视图控制器上都有一个 MOC 属性,这是那些认为应用程序委托不应该用于拥有单例 MOC 的人强烈推荐的,并且还有更多的实用程序能够为每个 VC 提供单独的 MOC。

    我相信您也可以在 IB 的情节提要中创建一个 MOC 实例。至少,笔尖总是有一个 MOC 对象。虽然我还没有充分使用它来了解它与编程核心数据堆栈的关系。在 VC 层次结构或应用程序委托中可以访问的某个地方可能最好只拥有一个 MOC 属性

    【讨论】:

    • 我尝试将 MOC 传递到一个插座,该插座是 NSManagedObjectContext 的 IB 实例,我厌倦了传递 NSPersistentDocument 并绑定到该插座,但都不起作用,所以我提交了 DTS 事件。我可以尝试只通过 MOC 而不是让它成为最后的出口可能会使控制拖动绑定更好地工作。
    • 我的理解是,在 IB 中添加 MOC 对象实际上会分配一个视图将拥有的 MOC,并在视图被释放时释放。无论您是否尝试将 IBOutlet 属性指向您以编程方式创建的不同 MOC,与该对象的绑定都可能指向视图拥有的对象——视图中的对象绑定到视图中的 MOC。我认为应用程序委托或一个或另一个控制器创建 MOC 并通过控制器绑定更直接。
    • 是的,我很确定我在 IB 中添加的 MOC 并没有更改为文档中的 MOC,即使我使用的是插座来设置它们。我也在 Apple Dev Forums 中问过这个问题,并得到了一个几乎可行的答案:将数组控制器的 MOC 绑定到运行它的视图控制器,键路径为 view.window.windowController.document.managedObjectContext。对于每个加载的选项卡,我仍然看到一个投诉,但之后它就可以工作了。最好的部分是仍然没有代码来获得一个超级简单的基于核心数据文档的应用程序!
    • 我完全错过了您使用基于文档的应用程序。如果你愿意,你可以自己回答。这是一种扩展评论。我要补充一点,您应该为 MOC 指针的视图或窗口控制器添加一个属性,以便您可以相对轻松地切换到一次性子上下文,如果您的应用程序开始从服务器加载数据,您可以将文档的 MOC 切换到私有队列,以及到 mainQueue 的 GUI MOC。您还可以为可以取消的用户输入生成子 MOC。在任何这些事件中,您都不需要更新 IB 中的绑定。
    • 我尝试将 managedObjectContext 对象添加到 ViewController 场景中。在一种情况下,App Delegate 突然变得可用于绑定,但我无法重现它。无论如何,IB moc 对象是无用的。您可以绑定到它,但它总是给出错误:“NSInternalInconsistencyException:无法执行操作,因为托管对象上下文没有持久存储协调器”。 moc 对象在 IB 中不可配置,子类化可能是一种解决方案。
    【解决方案4】:

    更新:

    @theMikeSwan,好吧,它几乎对我有用。这是我所拥有的:

    OSX EL Capitan GM Xcode 7GM 和 Xcode 7.1 测试版

    一个标准的 Coredata/Document 应用程序

    将 MainViewController 替换为 TabViewController 并添加 2 个 ViewControllers。

    在您的代码中添加了将代表对象放入 tabviewcontroller 的所有视图控制器中。

    第一个选项卡是一个带有表格的视图控制器,以及一个绑定到名为 Profiles 的实体的数组控制器,并且表格视图通过 +/- 等绑定到该控制器

    标签二是一个视图,视图控制器带有一个表,一个数组控制器绑定到一个名为 Commands 的实体,并且 tableview 绑定到该控制器。

    配置文件和名称为配置文件>命令的命令实体之间存在一对多关系。

    两个选项卡都按预期独立工作,没有错误 - 这意味着我可以在第一个选项卡的表中添加和删除 Profiles->name,我可以在第二个选项卡的表中添加和删除 Commands->name。

    接下来我想强制执行一对多关系 - 这意味着如果我在选项卡 1 的表中选择一个配置文件,然后切换到选项卡 2,我只想查看与该表中所选配置文件相关的命令。那是行不通的。在所有情况下都会显示所有输入的命令,我尝试过过滤谓词、获取谓词等,但都有不同程度的灾难。

    我已经尝试了所有我能想到的方法,还有很多我不想提及的技巧 -

    此时,我已将第二个 arrayController 添加到第二个选项卡视图并将其绑定到 Profiles 实体和 self.representedObject.managedObjectContext 等...我在第二个选项卡视图上添加了一个 NSTextField 并将其绑定到刚刚添加的profileArrayController -> selection -> name 看看控制器在想什么......

    无论我在第一个选项卡的表格中选择什么,第二个选项卡中的 Profile-> 名称都不会改变,它始终显示相同的 Profiles-> 名称。第二个选项卡中的表格中列出的命令不受第一个表格中的任何选择的影响。

    “感觉”第二个选项卡上的 MOC 与第一个选项卡上引用的 MOC 不同。但这只是一种感觉。我迷路了,关于如何在这样的多选项卡视图控制器设置上的选项卡之间建立一对多关系的任何建议?

    谢谢 弗兰克

    编辑添加:

    顺便说一句,我在其中一些选项卡上,例如命令选项卡,多个表在同一个选项卡上以一对多关系配置,可以正常工作 - 例如,我有一个同义词表,通过数组控制器绑定到同义词实体这是与指挥实体关系的多方面。只要表/数组控制器在同一个选项卡上,它就可以正常工作,但是在单独的选项卡上时,它就没有乐趣了。

    【讨论】:

    • 看看我的回答中提到绑定到self.representedObject.managedObjectContext 的部分。请务必使用显示的代码。在基于文档的核心数据世界中使用选项卡视图时,我也遇到了问题。 @marcus-s-zarra 写了一本关于 Core Data 的书,你也可以在他的博客上找到几篇关于它的文章。这些天来,我还有一些相当陈旧的微薄帖子,但在 www.theMikeSwan.com/blog/ 上仍有有用的信息。顺便说一句,这可能会更好地作为一个新问题。
    • 将我的问题描述更新为新信息 - 基本上,单独的 arrayControllers 似乎正在工作,但我需要它们以协调的方式跨选项卡工作 - 反映选项卡之间的一个 > 多个关系.
    • 两个阵列控制器在 MOC 级别看到相同的数据,问题是选择存储在阵列控制器而不是 MOC 中。为了让一个选项卡中的选择影响另一个选项卡中显示的内容,您需要添加一些内容,可能在选项卡之间存在的任何共享超级视图或窗口控制器中,以跟踪主选项卡中的选择,以便两者选项卡有一个沟通渠道。或者,您可以将实体添加到仅跟踪所选项目的模型中,然后使用它来控制第二个选项卡中显示的内容。
    • 非常感谢,这解释了我所看到的很多内容。我的印象是 MOC 包含选择,现在我想你所说的,这完全有道理。谢谢!
    • 一个答案是在您获得选择时发送“新选择发生”通知。然后,您的各种控制器可以侦听这些通知并进行相应更新。
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2012-10-23
    • 1970-01-01
    • 2011-03-16
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多