3
votes

I've written a macOS Document-type app with a storyboard, using the Xcode template, and somewhere along the line the association between the initial app launch and the document has varied from the expected pattern such that none of the NSDocument initializers I expect are called when the app first launches (but are called every new window thereafter).

I've subclassed all four documented NSDocument initializers, as follows:

public class Simulation: NSDocument {

        override init() {
        debugPrint("--------------------\(#file)->\(#function) called")
        super.init()
    }

    init(contentsOf: URL, ofType: String) throws {
        debugPrint("--------------------\(#file)->\(#function) called")
        fatalError()
    }

    init(for: URL?, withContentsOf: URL, ofType: String) throws {
        debugPrint("--------------------\(#file)->\(#function) called")
        fatalError()
    }
    convenience init(type: String) throws {
        debugPrint("--------------------\(#file)->\(#function) called, type: \(type)")
        self.init()
    }

    public override class func autosavesInPlace() -> Bool {
        debugPrint("--------------------\(#file)->\(#function) called")
        return false
    }
}

None of the inits exhibit the debugPrint output when the app launches. The app window is created successfully on launch, with no apparent document association.

However, I notice some really odd behavior I can't explain:

  1. Although I've seen no init call, autosavesInPlace is called three times after the app starts on some instance of the document
  2. When I use cmd-N (i.e., File->New and therefore newDocument()) to create a new document, autosavesInPlace is called three more times, and then the document init is executed!
  3. I never see a call to makeWindowControllers()

My NSDocument subclass is named Simulation. The anomaly seems to be that there's some magic in the initial startup that bypasses Simulation.init, but calls it every document+window creation thereafter.

Here are my questions:

  1. Why does the initial launch not call Simulation.init()?
  2. How does autosavesInPlace find an instance of Simulation to call when there's only that initial, seemingly partially constructed window?
1
autosavesInPlace is a class method, it is called on the class, not on an instance. Did you implement applicationShouldOpenUntitledFile?Willeke
It's awful that I missed autosavesInPlace being a class function. Not my day, I guess.. In any event, I had not implemented applicationShouldOpenUntitledFile. I did so in the app delegate, and a stub for its partner applicationOpenUntitledFile while I was there, and ran the app. Neither one was ever called - not when I launched the app, and not for cmd-N.Feldur
@Willeke - Specifically, when I start the app, I see this (added print in the VC) (I can't format as code!) ` "VC.swift->init(coder: called" "VC.swift->viewDidLoad() called" "VC.swift->viewWillAppear() called" "VC.swift->viewDidAppear() called"` However, using cmd-N I get this: ` "Simulation.swift->init(type:) called, type: Effie.Simulation" "Simulation.swift->init() called" "Simulation.swift->makeWindowControllers() called" "VC.swift->init(coder: called" "VC.swift->viewDidLoad() called" "VC.swift->viewWillAppear() called" "VC.swift->viewDidAppear() called"`Feldur
We can't guess what the unidentified change in the storyboard is. Create a new test project and compare. Put a break on init(type:).Willeke
I can't guess either, and init(type:) wasn't called for the initial window - that's sort of why I can't figure this out!Feldur

1 Answers

7
votes

In your storyboard, make sure both your Window Controller and its Content View Controller have Is Initial Controller unchecked and Presentation set to Multiple in the Attributes Inspector.

Window Controller Attributes Inspector image

View Controller Attributes Inspector image

Having Is Initial Controller checked will cause the application to instantiate one window controller before any of the NSDocument/NSDocumentController "magic" happens. Presentation: Multiple should be selected for coherence, although it might not really make a difference.

Also, make sure your document types are properly setup in Info.plist, particularly the NSDocumentClass key (should contain $(PRODUCT_MODULE_NAME).Simulation).

I believe your question about autosavesInPlace is already answered in the comments…