OS X Core Data - 将托管对象上下文传递给视图控制器
Posted
技术标签:
【中文标题】OS X Core Data - 将托管对象上下文传递给视图控制器【英文标题】:OS X Core Data - Passing a Managed Object Context to a View Controller 【发布时间】:2016-06-13 12:12:45 【问题描述】:我正在 Xcode 7.3.1 中开发 Mac 应用程序。我正在尝试将模型对象上下文从我的 AppDelegate 传递给 ArrayController。
我有一个名为 DataController 的类,它创建了我的核心数据堆栈。 DataController.managedObjectContext 保存托管对象上下文。
我的 AppDelegate 类如下:
class AppDelegate: NSObject, NSApplicationDelegate
var dataController: DataController!
func applicationDidFinishLaunching(aNotification: NSNotification)
// Insert code here to initialize your application
// Create an instance of the DataController class.
dataController = DataController()
// Create a reference to the first ViewController embedded in the WindowController.
guard let splitViewController = NSApplication.sharedApplication().windows[0].contentViewController as? ManagedObjectContextSettable
else fatalError("Wrong view controller type")
// Set the managedObjectContext property.
splitViewController.managedObjectContext = dataController.managedObjectContext
func applicationWillTerminate(aNotification: NSNotification)
// Insert code here to tear down your application
在我的故事板中,我在 WindowController 中嵌入了一个 SplitViewController。 SplitViewController 有自己的自定义视图控制器类,名为 SplitViewController。这是SplitViewController中的代码:
class SplitViewController: NSSplitViewController, ManagedObjectContextSettable
var managedObjectContext: NSManagedObjectContext!
override func viewDidLoad()
super.viewDidLoad()
// Do view setup here.
// Create a reference to the first ViewController embedded in the WindowController.
let childControllers = self.childViewControllers
print("childControllers.count = \(childControllers.count)")
for childController in childControllers
if childController.isKindOfClass(TableViewController)
print("Found TableViewController")
guard let tableViewController = childController as? ManagedObjectContextSettable
else fatalError("Wrong view controller type")
tableViewController.managedObjectContext = managedObjectContext
其中一个拆分视图项是我的 TableView,它有自己的视图控制器,名为 TableViewController。下面是 TableViewController 的代码:
class TableViewController: NSViewController, ManagedObjectContextSettable, NSTableViewDataSource, NSTableViewDelegate
@IBOutlet weak var tableView: NSTableView!
var managedObjectContext: NSManagedObjectContext!
override func viewDidLoad()
super.viewDidLoad()
// Do view setup here.
//print(managedObjectContext.description)
在情节提要中,我拖动了一个 ArrayController,在 Inspector 的 Bindings 选项卡中,我设置了 Bind To 并选择了 TableViewController 并将 Model Key Path 设置为“self.managedObjectContext”。最终它没有收到托管对象上下文。
我无法确定是否应该为嵌入式 ViewController 重写 prepareForSegue 函数,我阅读的每个示例都是针对 ios 的。
请问我哪里出错了?
【问题讨论】:
【参考方案1】:applicationDidFinishLaunching
可以在viewDidLoad
之后执行。当设置了 splitViewController 的managedObjectContext
时,设置了 childControllers 的managedObjectContext
。
绑定使用 KVO。将 var managedObjectContext
更改为 dynamic var managedObjectContext
以使属性符合 KVO。
【讨论】:
我注意到 AppDelegate.applicationDidFinishLoading 是在 ViewController 的所有 viewDidLoad 方法之后执行的。您是否建议我在 AppDelegate.applicationDidFinishLoading 方法中设置 SplitViewController 的子视图控制器(TableViewController)的 managedObjectContext 变量? 我建议viewDidLoad
的SplitViewController
可以在viewDidLoad
的TableViewController
之前执行。实现managedObjectContext
的setter并传播到childControllers。
另一种可能的解决方案是以编程方式将数组控制器的managedObjectContext
绑定到dataController.managedObjectContext
。 (我认为情节提要和视图控制器的开发人员从未听说过绑定)【参考方案2】:
如果您使用带有 Cocoa 绑定的数组控制器,您必须重写 init(coder:)
方法并在那里初始化托管上下文以执行隐式初始获取。 viewDidLoad
来不及了。
segue 工作流程与 iOS 中的相同。更方便,因为有一个属性presentingViewController
可以获取对父视图控制器的引用。
Core Data Manager DataController
应该是一个单例,以确保托管对象上下文实例始终相同。
【讨论】:
非常有帮助。那我是不是重写AppDelegate中的init将MOC传递给SplitViewController,然后重写SplitViewController中的prepareForSegue将MOC传递给TableViewController? 不在 AppDelegate 中,仅在使用数组控制器和绑定的控制器中。如果使用单例,则在 AppDelegate 中初始化堆栈,然后从单例中获取上下文。 我直接在 ArrayController 所在的控制器中创建了我的 DataController 类的实例。那么为什么 Apple 建议我将 MOC 从 AppDelegate 传递给 Window 的子视图控制器,并从它们向下传递给它们的子视图? Apple 不建议使用自定义核心数据控制器类的不同实例。您可以按照推荐的方式将核心数据代码保留在 AppDelegate 中并分别传递托管上下文,但是您必须执行额外的“手动”获取,因为绑定是在调用viewDidLoad
之前建立的。
fetch:
被推迟到运行循环的下一次迭代。在applicationDidFinishLaunching
中设置managedObjectContext 已经足够早了。【参考方案3】:
这可能不是一个好的做法,但它似乎有效。
我将我的 DataController 类设为单例类,以确保只有一个托管对象上下文。在我的 TableViewController 中,我创建了一个 managedObjectContext 属性,如下所示:
lazy var managedObjectContext = DataController.sharedInstance.managedObjectContext
在我的数组控制器中,我将托管对象上下文参数绑定到 TableViewController 并将模型键路径设置为 self.managedObjectContext。
可以改进吗?
【讨论】:
以上是关于OS X Core Data - 将托管对象上下文传递给视图控制器的主要内容,如果未能解决你的问题,请参考以下文章
在后台线程上安全保存 Core Data 托管对象上下文的正确方法?