【问题标题】:OS X Core Data - Passing a Managed Object Context to a View ControllerOS X Core Data - 将托管对象上下文传递给视图控制器
【发布时间】: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 的。

请问我哪里出错了?

【问题讨论】:

    标签: macos core-data cocoa-bindings


    【解决方案1】:

    applicationDidFinishLaunching 可以在viewDidLoad 之后执行。当设置了 splitViewController 的managedObjectContext 时,设置了 childControllers 的managedObjectContext

    绑定使用 KVO。将 var managedObjectContext 更改为 dynamic var managedObjectContext 以使属性符合 KVO。

    【讨论】:

    • 我注意到 AppDelegate.applicationDidFinishLoading 是在 ViewController 的所有 viewDidLoad 方法之后执行的。您是否建议我在 AppDelegate.applicationDidFinishLoading 方法中设置 SplitViewController 的子视图控制器(TableViewController)的 managedObjectContext 变量?
    • 我建议viewDidLoadSplitViewController 可以在viewDidLoadTableViewController 之前执行。实现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。

    可以改进吗?

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2023-03-14
      • 1970-01-01
      • 2010-12-16
      • 1970-01-01
      • 2012-10-23
      • 1970-01-01
      相关资源
      最近更新 更多