Home > Back-end >  How can I read and get notified a computed property of a class in cocoa macos?
How can I read and get notified a computed property of a class in cocoa macos?

Time:02-05

In NSWindow class there is a computed property called isVisible, I am creating a custom NSWindow and i am calling it MyNSWindow so I want look the value change of isVisible for MyNSWindow, for example the value should be false before window get available in screen, and after that the value should be true, so I want observe this value change, how can i do this? Also I am not looking for an answer with Combine.

This is my code:

import Cocoa

class AppDelegate: NSObject, NSApplicationDelegate {
    
    private var window: NSWindow!
    
    func applicationDidFinishLaunching(_ aNotification: Notification) {

        window = MyNSWindow(
            contentRect: NSRect(x: 0, y: 0, width: 100.0, height: 100.0),
            styleMask: [.titled, .closable, .miniaturizable, .resizable, .fullSizeContentView],
            backing: .buffered, defer: false)
        
        window.setFrameAutosaveName("Main Window")
        window.title = "No Storyboard Window"
        window.makeKeyAndOrderFront(window)
        window.center()
        
    }

}


class MyNSWindow: NSWindow {
    
 
    
}

CodePudding user response:

Apple has made it difficult to reliably be notified when a window becomes visible or hidden. I've done some investigating for my own project, and here's what I've discovered:

  • Apple's recommended solution is to set an NSViewController as the window's contentViewController. Override the view controller's viewWillAppear or viewDidAppear method to be notified when the window becomes visible. Override the view controller's viewWillDisappear or viewDidDisappear method to be notified when the window becomes hidden.

    I know this is Apple's recommend solution because I opened a feedback (in 2016) requesting a public windowWillShow notification and was told:

    Our more modern way of doing this is to use Storyboards with a View Controller; the contentViewController will get a viewWillAppear — this is the hook you should be using now.

    As far as I know from very limited testing, this method is reliable, so it may work well for you. I have an existing app with many windows that were implemented without contentViewControllers that I do not wish to retrofit, so this doesn't work well for me. Also, you can only apply this to windows you create—not, for example, to the window created by NSAlert.

  • visible is not KVO-compliant.

  • There are no documented notifications posted when visible changes from false to true.

  • The NSWindow.willCloseNotification is supposed to be posted when visible changes from true to false, but it doesn't get posted when a window presented as a sheet is dismissed.

  • It should be possible to use Cocoa Bindings to bind to visible (using the NSVisibleBinding constant), but the binding is not updated when a window presented as a sheet is dismissed. It is also annoying and obscure to implement.

  • There is no single, public “funnel” method you can override on NSWindow to be notified. The orderOut(_:), orderFront(_:), and orderBack(_:) methods do go through order(_:relativeTo:), but orderFrontRegardless() does not. Sheet presentation and dismissal do go through order(_:relativeTo:), so if you never use orderFrontRegardless(), making an NSWindow that overrides order(_:relativeTo:) may be a good solution for you. You will not, however, be notified of the appearance and disappearance of windows created by AppKit for you, such as the window created by NSAlert. If you create any NSPanels, you'll also want to create an NSPanel subclass.

  • AppKit posts a number of undocumented notifications when windows change visibility, that are posted reliably even for sheet presentation and dismissal. Two of these are named _NSWindowWillBecomeVisible and NSWindowWillOrderOffScreenNotification. Use at your own risk.

  • Related