打开基于NSDocument的应用程序会加载两个窗口

时间:2019-04-26 15:41:04

标签: swift macos nsdocument

我有一个简单的基于NSDocument的应用程序,其中有两个文本字段(想象一下git不同)。当我打开文件时,它会打开两个带有文件名的窗口。在第一个窗口上,一切都很好。第二个用户界面空白,文件名相同。

override func makeWindowControllers() {
    // Returns the Storyboard that contains your Document window.
    let storyboard = NSStoryboard(name: NSStoryboard.Name("Main"), bundle: nil)
    let windowController = storyboard.instantiateController(withIdentifier: NSStoryboard.SceneIdentifier("Document Window Controller")) as! NSWindowController
    self.addWindowController(windowController)
}

override func read(from data: Data, ofType typeName: String) throws {

    if let fileString = String(data: data, encoding: String.Encoding.utf8) {

        makeWindowControllers()

        guard let vc = windowControllers.first?.contentViewController as? ViewController else {
            throw NSError(domain: NSOSStatusErrorDomain, code: unimpErr, userInfo: nil)
        }

        guard let inputString = String(data: data, encoding: .utf8) else {
            throw NSError(domain: NSOSStatusErrorDomain, code: unimpErr, userInfo: nil)
        }

        let doc = JsonConverter().convertToJSONFrom(string: inputString)

        if let a = doc["a"] as? String {
            vc.leftTextView.string = a
        }

        if let b = doc["b"] as? String {
            vc.rightTextView.string = b
        }

    } else {
        throw NSError(domain: NSOSStatusErrorDomain, code: unimpErr, userInfo: nil)
    }
}

Main UI

我不知道第二个(右边)的来源。

编辑:我刚刚注意到,如果我双击一个保存的文件,则会收到此错误,奇怪的是,该错误不会从read()函数中的任何NSError中触发。

首先,从菜单中打开是我上面所指的。

编辑2:更正。 “有时”它会打开两个窗口。但是即使这样做,两者都是空的。我没有得到的是,这个读取功能是如此简单,没有太多出错。感觉这一切都在引擎盖下横摆。

Error when double clicking file.

1 个答案:

答案 0 :(得分:1)

  

我不知道第二个(右边)的来源。

它似乎可能来自您的read()函数,该函数调用makeWindowControllers()。来自the documentation

  

该方法由NSDocumentController open ...方法调用,但是您可能希望在某些情况下直接调用它。

打开文档时,当然也会读取它,因此makeWindowControllers()被调用两次:一次是通过文档的内置打开行为,一次是通过您的read()覆盖。

  

更正。 “有时”它会打开两个窗口。但是,即使这样做,两者都是空的。

也许您偶尔遇到一个错误,导致文档甚至无法进行read()调用。

  

如果我双击保存的文件,则会出现此错误

这支持这样的想法:在您进入read()之前,出现了问题。您可以通过在read()中放置一条日志消息并在仅打开一个窗口的情况下在控制台中检查该消息来轻松地找到消息。另外,您的应用程序委托中是否有任何application(open...)方法被覆盖?也许其中之一是导致错误的原因。

更新

在处理了一个简单的基于文档的项目后,我发现NSDocument确实确实为您调用了makeWindowControllers(),但在之后调用了{ {1}}。 read()方法中的断点将显示没有视图控制器,因为尚未调用read()。这是我的makeWindowControllers()方法:

read()

如果我取消对override func read(from data: Data, ofType typeName: String) throws { // makeWindowControllers(); guard let text = String(bytes: data, encoding: .utf8) else { return } self.content = text } 的调用的注释,则会收到与您询问的症状相同的信息:两个窗口打开,只有其中一个显示内容。但是,如果我创建一个新文档,则只会得到一个窗口,因为从未调用makeWindowControllers()方法。

  

因此,此应用目前非常基本。视图控制器有两个出口,并在NSTextViewDelegate的textDidChange函数中设置文本。就是这样。默认为应用程序委托,然后为Document类。如果我不调用makeWindowControllers,则windowControllers为空。如果我叫它,那么我有1个控制器,这就是我用来更新UI的控制器。不太确定如何解决这个问题。

您正尝试在read()方法中做太多事情。 read()非常面向MVC,您可以将文档视为一种控制器-将视图和数据联系在一起。 NSDocument方法旨在让您读取数据,并且在此之后才创建视图。我认为这可能是因为数据可能确定要创建哪种视图。我的文档类有一个read()属性,它只是一个字符串,而content只是从文件中获取数据并将其粘贴在字符串中。在我的情况下,read()被自动为我呼叫,而我的覆盖使用makeWindowControllers()来设置窗口:

content
  

此外,如果我注释掉对makeWindowControllers的调用,则在打开文件时永远不会调用它。记录证明,手动调用只调用一次,没有手动调用则为零。

如果您的日志语句位于override func makeWindowControllers() { // Returns the Storyboard that contains your Document window. let storyboard = NSStoryboard(name: NSStoryboard.Name("Main"), bundle: nil) let windowController = storyboard.instantiateController(withIdentifier: NSStoryboard.SceneIdentifier("Document Window Controller")) as! WindowController windowController.text = self.content self.addWindowController(windowController) } 中,则对此没有很好的解释。它与我所看到的不一致,所以请您a)检查您的工作,b)在评论或您的问题中在此处添加更多信息。同样,我看到makeWindowControllers()被调用而无需显式调用。