Restoring nested NSDocuments

96 Views Asked by At

I am working on an Xcode-like IDE for MacOS. The IDE opens source files (instances of TextDocument) and has a separate project file (an instance of ProjectDocument that contains project settings. Both are subclasses of NSDocument.

When a source file is open, the WindowsController and contentViewController still need access to the project file.

The way I initially solved this, is by adding a var project: ProjectDocument? property to TextDocument. So that every source file has a pointer to the project document. The representedObject property of the view controller is set to the text document.

This works well when creating, opening and saving files.

However, restoring windows after reopening the app doesn't work flawlessly.

The TextDocument (set to representedObject) gets restored correctly, but the project property doesn't. Something does get saved, because if coder.containsValue(forKey: "project") returns true in the restoreState(with coder: NSCoder) method, but a subsequent self.project = coder.decodeObject(forKey: "project") as? ProjectDocument return nil. As if the encoding is a different format than the decoding expects.

If I change ProjectDocument so it inherits from NSObject instead of NSDocument, the project does get restored correctly.

So the issue seems to be encoding NSDocument instances.

I've also tried to store the project file as a separate property of the view controller, but that has the same issue. Somehow, NSDocuments don't like to be encoded it seems.

final class TextDocument: NSDocument {
    @objc var project: ProjectDocument? = nil

    override func encodeRestorableState(with coder: NSCoder) {
        coder.encodeConditionalObject(self.project, forKey: "project")
        super.encodeRestorableState(with: coder)
    }

    override func restoreState(with coder: NSCoder) {        
        super.restoreState(with: coder)
        if coder.containsValue(forKey: SerializationKey.project) {
            self.project = coder.decodeObject(forKey: "project") as? ProjectDocument // Is always nil
        }
    }
}

// NSDocument subclass can't be restored
final class ProjectDocument: NSDocument {

}

// NSObject subclass can.

final class ProjectDocument: NSObject, NSCoding {

}

I expect the project property of the TextDocument to be restored. It isn't

0

There are 0 best solutions below