I'm creating a MacOS document-based app in Swift. When running the app, if I make modifications to the document, and then select "Revert to Saved", I get a dialog asking me if I want to revert the document, losing current changes, but if I click on "Revert", nothing happens. The document keeps its changes.
Furthermore, after clicking Revert, the document behaves as if there are no changes -- the titlebar icon is not grey; and the window closes without asking to save changes (I'm not using Autosave). It's like ChangeCount or isDocumentEdited have been reset.
If I don't select Revert, then closing the document's window with unsaved changes brings a dialog asking to save.
Apple's documentation for .revertToSaved reads as follows:
The default implementation of this method presents an alert dialog giving the user the opportunity to cancel the operation. If the user chooses to continue, the method ensures that any editor registered using the Cocoa Bindings
NSEditorRegistration
informal protocol has discarded its changes and then invokes revert(toContentsOf:ofType:)
. If that returns false
, the method presents the error to the user in an document-modal alert dialog.This suggests to me that it should work without needing to be overridden.
Any idea why this is happening? Do I need to override the revert method to load the data back from disk?
I've not yet sorted out Undo for the app, which might be relevant. But I am using ChangeCount to check whether edits have been made.
hi,
after reading John's reply and then your code above, i'm sorry now to say that the advice i was offering was only correct if you were following MVC/iOS paradigm. i assumed you were. my apologies for not fully finishing the code.
John is right on three fronts:
(1) MacOS is becoming more iOS-like; the notions of an NSViewController even being in the responder chain and having viewWillAppear() and viewDidAppear() were only introduced maybe 4 years ago.
(2) your code is setting up its views to have direct references to the things they draw (along with some parameters). when the NSDocument is reverted, you're not telling the views that their references must be updated first before the views are redrawn.
(3) you need to set up references for the NSViews outside of viewDidAppear(). in fact, i don't see that you even want to touch viewDidAppear(). then you can call that code both upon startup and when revert happens.
so, based on your question and seeing your most recent code above, John's asking you to rewrite this way:
override func viewDidLoad() {
super.viewDidLoad()
NotificationCenter.default.addObserver(self, selector: #selector(handleDocumentReverted), name: .documentReverted, object: nil)
loadViewParameters()
}
func loadViewParameters() {
let theThumbnailSize = CGSize(width: 200, height: 200)
self.thePDFView?.document = document?.thePDFDocument
// self.thePDFView?.autoScales = true
self.thePDFView?.displayMode = theDisplayMode
self.thePDFView?.displaysAsBook = bookState
self.theThumbnailView?.pdfView = self.thePDFView
self.theThumbnailView?.thumbnailSize = theThumbnailSize
}
@objc func handleDocumentReverted(_ note: Notification) {
// i mentioned that you may not have to check directly in some cases
// whether you're responding to the right document's revert in these 2 lines:
// let sendingDocument = note.object as? Document
// guard sendingDocument == document else { return }
loadViewParameters()
thePDFView.setNeedsDisplay(thePDFView.bounds)
theThumbnailView.setNeedsDisplay(theThumbnailView.bounds)
}
hope that helps,
DMG