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

问题描述 投票:0回答:1

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

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()函数中的任何NSErrors中触发。

Fwiw,从菜单中打开就是我上面提到的。

编辑2:更正。 “有时候”会打开两扇窗户。但即使这样做,两者都是空的。我没有得到的是这个读取功能如此简单,没有太大的问题。感觉就像在引擎盖下侧面。

Error when double clicking file.

swift macos nsdocument
1个回答
1
投票

我没有得到第二个(右边)来自哪里。

看起来它可能来自你的read()函数,它调用makeWindowControllers()。来自the documentation

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

当文档被打开时,它当然也被读取,所以makeWindowControllers()被调用两次:一次是文档的内置打开行为,一次是你的read()覆盖。

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

也许你偶尔会遇到错误,导致文档无法进入read()调用。

如果我双击保存的文件,我会收到此错误

这支持了在你到达read()之前出现问题的想法。您可以通过在read()中放置日志消息并在仅打开一个窗口的情况下检查控制台中的消息来轻松找到。此外,您是否在您的应用程序委托中覆盖了任何application(open...)方法?也许其中一个人对错误负责。

更新:

在用简单的基于文档的项目搞砸了一下之后,我发现NSDocument确实为你调用了makeWindowControllers(),但它在调用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()的调用,我会得到你所询问的相同症状:打开两个窗口,其中只有一个显示内容。但是,如果我创建一个新文档,我只会得到一个窗口,因为read()方法永远不会被调用。

所以这个应用程序在这一点上非常基础。 View控制器有几个插座,并在NSTextViewDelegate的textDidChange函数中设置文本。但就是这样。 App委托默认,然后是Document类。如果我不调用makeWindowControllers,那么windowControllers为空。如果我调用它,那么我有1个控制器,这是我用来更新UI的。不确定如何解决这个问题。

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

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)
}

另外,如果我注释掉对makeWindowControllers的调用,那么当我打开文件时它永远不会被调用。记录证明它只用手动调用调用一次,没有它就调用零次。

如果您的日志声明在makeWindowControllers()中,我对此没有很好的解释。这与我所看到的不一致,因此我要求你a)检查你的工作,并在这里添加更多信息,无论是在评论中还是在你的问题中。再一次,我看到makeWindowControllers()被调用而不需要明确地调用它。

© www.soinside.com 2019 - 2024. All rights reserved.