xcode 将 NSArrayController 绑定到 Core Data 文档的托管对象上下文的新方法是什么?

声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow 原文地址: http://stackoverflow.com/questions/28184218/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me): StackOverFlow

提示:将鼠标放在中文语句上可以显示对应的英文。显示中英文
时间:2020-09-15 06:33:13  来源:igfitidea点击:

What is the new way of binding an NSArrayController to the managed object context of a Core Data document?

xcodecore-datainterface-buildercocoa-bindings

提问by theMikeSwan

Before Xcode went and added Storyboards for OS X apps you could connect an array controller to your document's managed object context by binding the Managed Object Contextof the array controller to File's Ownerwith a Model Key Pathof managedObjectContext. With storyboards there is no more File's Ownerso where do you get the context from now?

之前Xcode中去,并添加故事板为OS X程序,你可以通过绑定连接的阵列控制器到您的文档的管理对象上下文Managed Object Context阵列控制器来File's Owner使用Model Key PathmanagedObjectContext。有了故事板,就没有了,File's Owner那么从现在开始你从哪里获得上下文呢?

Apple's documentation is behind in this area and there aren't any obvious places to bind to in Xcode. Obviously I can just fall back to a non-storyboard route and use the old method, but there must be a new way of doing it.

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

采纳答案by theMikeSwan

So I have the answer from Apple. This is for Document based Core Data apps, the code is all in Swift but the idea is the same in Objective-C you just have to translate it.

所以我从苹果那里得到了答案。这是针对基于文档的 Core Data 应用程序的,代码都是在 Swift 中编写的,但在 Objective-C 中的想法是相同的,你只需要翻译它。

The first answer they gave me was to bind the array controller to the view controller running the view with a model key path of self.view.window.windowController.document.managedObjectContex. The sample I was shown used this method and had no error messages at all, it was however a single view controller inside the window controller with one array controller. My setup is a window to a tab view to the views with two array controllers in the one scene. I was still getting Cannot perform operation without a managed object contextonce each time a new document was opened or created. The second solution, that worked for me was to still bind the array controller to the view controller but with a model key path of self.representedObject.managedObjectContextand then to add to the end of the document class's makeWindowControllers()function:

他们给我的第一个答案是将数组控制器绑定到运行视图的视图控制器,模型键路径为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
    }
}

This solved the issue for me. Hopefully there is enough info here to show up when others google this issue.

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

回答by Sandy Chapman

Using the default Xcode generated project and including CoreData puts the managedObjectContextmember on the AppDelegate. You can add the following code to your ViewController, then use managedObjectContextas the "Model Key Path" with binding to ViewControllerfor your NSArrayController.

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

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

This simply creates a member which redirects to where your actual MOC is stored. This is useful because the NSArrayController binding happens before viewDidLoad(), hence why an instance member will not suffice. Also, if you want to refactor to a singleton CoreDataManagerclass, you can just change where to redirect to. Additionally, you could add this as a class extension to enable all ViewControllersto access your MOC.

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

Objective-C version upon request:

应要求提供 Objective-C 版本:

@interface MyViewController ()

@property (nonatomic, readonly) NSMangedObjectContext* managedObjectContext;

@end

@implementation MyViewController

- (NSManagedObjectContext*)managedObjectContext
{
    return ((AppDelegate*)([NSApplication sharedApplication].delegate)).managedObjectContext;
}

...

@end

回答by Frank Nichols

Updated:

更新:

@theMikeSwan, well, it almost works for me. Here is what I have:

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

OSX EL Capitan GM Xcode 7GM and Xcode 7.1 beta

OSX EL Capitan GM Xcode 7GM 和 Xcode 7.1 beta

A standard Coredata/Document application

标准的 Coredata/Document 应用程序

Replaced MainViewController with TabViewController and added 2 ViewControllers to that.

用 TabViewController 替换 MainViewController 并添加了 2 个 ViewControllers。

Added in your code to put representedObject in all view controllers in the tabviewcontroller.

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

Tab one is a view controller with a table, and an array controller that is bound to an entity called Profiles and the tableview is bound to that controller with +/- etc

选项卡一是一个带有表的视图控制器,一个数组控制器绑定到一个名为 Profiles 的实体,tableview 绑定到那个控制器,带有 +/- 等

Tab two is a view with view controller with a table, and an array controller that is bound to an entity called Commands and the tableview is bound to that controller.

选项卡二是一个带有表的视图控制器的视图,以及一个绑定到名为 Commands 的实体的数组控制器,并且表视图绑定到该控制器。

There is a one to many relationship between the Profiles and the Commands entities with the names profiles <->> commands.

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

Both tab's work as expected with no errors independently - meaning I can add and delete Profiles->name in the table in the first tab, and I can add and delete Commands->name in the table in the second tab.

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

Next I want to enforce the one to many relationship - meaning if I select a Profile in the table in tab 1, and then switch to tab two, I want to see only the commands related to the selected profile in that table. That does not work. All entered Commands are shown in all cases, I have tried filters predicates, fetch predicates, etc, with varying degrees of disaster.

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

I have tried everything I can think of, and a lot of hacks I would rather not mention -

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

At this point I have added a second arrayController to the second tab view and bound it to Profiles entity and with self.representedObject.managedObjectContext etc... I added a NSTextField on the second tab view and bound it to the just added profileArrayController -> selection -> name to see what the controller was thinking...

在这一点上,我在第二个选项卡视图中添加了第二个 arrayController 并将其绑定到 Profiles 实体和 self.representedObject.managedObjectContext 等......我在第二个选项卡视图上添加了一个 NSTextField 并将其绑定到刚刚添加的 profileArrayController ->选择 -> 名称以查看控制器在想什么...

The Profile->name in the second tab never changes regardless of what I select in the first tab's table, it is always showing the same Profiles->name. The commands listed in the table in the second tab are not affected by any selection in the first table.

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

It "feels" like the MOC on the second tab is not the same as the MOC referenced by the first tab. But that is just a feeling. I am lost, any suggestions on how to do a one to many relationship across tabs on a multi-tab view controller setup like this?

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

thanks Frank

谢谢弗兰克

Edited to add:

编辑添加:

BTW, I have on some of those tabs, like the command tab multiple tables configured in one to many relationships on the same tab that work correctly - for example I have a synonyms table with bindings to a synonym entity via an array controller which is a many side of a relation ship with the command entity. It works fine as long as the tables/arraycontrollers are on the same tab, but when on separate tabs it is no joy.

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

回答by stevesliva

You have always been able to bind through NSApplication with a keypath of delegate.managedObjectContext if the application delegate owns the core data stack. Otherwise you could pass pass the MOC through to each view controller with a MOC property on each one, which is strongly preferred by those who argue that the app delegate shouldn't be used to own singleton MOCs, and that there's further utility in being able to provide each VC a separate MOC.

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

I believe you could also create a MOC instance in the storyboard in IB. There's also always been a MOC object for nibs, at least. Though I haven't used that enough to know how it relates to a programmatic core data stacks. Probably better to just have a MOC property somewhere you can access in either the VC hierarchy or app delegate

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