Post not yet marked as solved
Thanks. But I have to say I find some of Apple's prose to be very oblique. "A Binding is a keypath FOR a property of a receiver, and a keypath is a key path TO a property reachable from a Controller."OK, let's get more technical. I have a PDFThumbnailView that (when an IBAction is executed) needs to pass its array of .selectedPages to Document.swift, where the related PDFPage object will be rotated, deleted, inserted etc. Then the View needs to be updated.So is the keyPath the actual property (.selectedPages) in ViewController, and the Binding is just a name for it in Document.swift (which is the receiver)?
Post not yet marked as solved
Yes, MacOS, Swift, document-based app. I've not used SwiftUI -- would I have to recreate my existing UI?
DMG, you have nothing to apologise for! If there's any fault, it's in my not supplying enough relevant code to start with. (Though, of course, knowing what's relevant is half the battle.)Your code worked with one alteration: As is, I got a blank grey window at launch. By including loadViewParameters in viewWillAppear() as well as in the Revert Handler, it works perfectly! Nothing was needed in viewDidLoad except the Notification. (In fact, the super isn't even necessary -- according to Apple, the default implementation does nothing.)So I'm going to mark it as the correct answer.Right, onto Undo! 😕
John, Many thanks for this. (You should be able to Rotate and Delete pages in the app.)Can you clarify "You are initializing your PDF view in viewDidAppear. That isn't getting called as a side effect of revert."?I tried moving everything from viewDidAppear to viewDidLoad, but I just got a grey window.I've no objection to using NSDocument 'the right way', I'm just using it as minimally as I can to get it working. As the app grows, no doubt that will change. I've read Apple's pages on NSDocument, which describes a text doc, and I can't always see how it applies.I know it's a "long-term project": but I've been filing BRs and ERs about Preview for 10 years, so... 😁 // OVERRIDES
override func viewDidLoad() {
super.viewDidLoad()
NotificationCenter.default.addObserver(self, selector: #selector(handleDocumentReverted), name: .documentReverted, object: nil)
// Do any additional setup after loading the view.
}
override func viewDidAppear() {
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
}
override var representedObject: Any? {
didSet {
// Update the view, if already loaded.
}
}
Thanks. I put a log message into the handle function, after the setNeedsDisplay, and it logs, but still the view remains unchanged.If I save the PDF, I get the reverted version.You 've been amazingly helpful, and I can't really ask you for more. I'm tempted to mark this as the correct answer, even if it doesn't work fo me.If I try to put a link to the github repository for the project, my post gets held in a "waiting for moderation" queue.
I don't understand how ViewController can talk about documents but Document can't talk about views.In ViewController.swift, I have:var document: Document? {
return self.view.window?.windowController?.document as? Document
}which I use so that the methods in VC can do things like document.updateChangeCount. Or should I be using Notifications for that?Can I use that to help with identifying the correct document that sent the Notification?Back in Document.swift, I now have: NotificationCenter.default.post(name: Notification.Name("Revert!"), object: Document.self)in my revert function. Over in ViewController.swift viewDidLoad, I have: NotificationCenter.default.addObserver(self, selector: #selector(updateUI), name: Notification.Name("Revert!"), object: Document.self)and then elsewhere:@objc func updateUI() {
thePDFView.setNeedsDisplay(thePDFView.bounds)
}But still nothing changes. (God these code boxes are awful.)
Thanks. Yes, I'm likely to have more than one document open, so that's going to be an issue. I've been looking at Stack Overflow:https://stackoverflow.com/questions/44561256/how-to-reload-or-update-a-viewcontrollers-view-once-a-file-is-savedwhich provides some swift code for notifications. Could I not just have a binding from my PDFView to the PDFDocument?
I can reload the view with the following code: var viewController: ViewController? { return windowControllers[0].contentViewController as? ViewController } override func revert(toContentsOf url: URL, ofType typeName: String) throws { do { try super.revert(toContentsOf: url, ofType: typeName) viewController?.viewDidAppear() }}But I get a log message telling me that I shouldn't load a view that's already loaded. I can't find a method for REloading the viewcontroller. Trying to run setNeedsDisplay on a particular view of the viewcontroller didn't work.
Thanks for this: I'll see if I can swiftify it. But I think the problem is that I haven't subclassed NSDocument sufficiently with KVO stuff, so "do anything you normally need to do with your windowcontroller" is the tricky bit, as I can't refresh the view.Revert is working on the Data level, but not on the View level.
Thanks, John. It seems every time I get so far, the finishing tape gets moved further back! 😁Xcode has come a long way from MPW, but I kind of expected more of these APIs to 'just work', rather than having to rewrite them.
The code works: it just doesn't do what I want.
How can the reverttoSaved meothd of NSDocument refresh the view it's in, then?My ViewController uses:var document: Document? { return self.view.window?.windowController?.document as? Document }to get the document data.
Here's my code: var viewController: ViewController? { return windowControllers[0].contentViewController as? ViewController } override func revert(toContentsOf url: URL, ofType typeName: String) throws { do { try super.revert(toContentsOf: url, ofType: typeName) let docsview = viewController?.view docsview?.setNeedsDisplay(docsview!.bounds) } }It still doesn't update the view.
I'm using PDFDocument as my data model, so that's under control. I'm familiar with that from python.I mostly have problems due to the separation of data and view (which I realise is a good thing). How I get the document to control the view, I'm not sure. Next step is to sort out Undo, and I'm not looking forward to that!
Thanks. This is where I stumble conceptually, as the revert function is in Document.swift, and the view stuff is obviously in ViewController.swift. But I'm sure I'll find a way.Is restoreWindow method something to try? Not sure what the parameters would be, though.