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'scontentViewController
. Override the view controller'sviewWillAppear
orviewDidAppear
method to be notified when the window becomes visible. Override the view controller'sviewWillDisappear
orviewDidDisappear
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
contentViewController
s 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 byNSAlert
.visible
is not KVO-compliant.There are no documented notifications posted when
visible
changes fromfalse
totrue
.The
NSWindow.willCloseNotification
is supposed to be posted whenvisible
changes fromtrue
tofalse
, 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 theNSVisibleBinding
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. TheorderOut(_:)
,orderFront(_:)
, andorderBack(_:)
methods do go throughorder(_:relativeTo:)
, butorderFrontRegardless()
does not. Sheet presentation and dismissal do go throughorder(_:relativeTo:)
, so if you never useorderFrontRegardless()
, making anNSWindow
that overridesorder(_: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 byNSAlert
. If you create anyNSPanel
s, you'll also want to create anNSPanel
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
andNSWindowWillOrderOffScreenNotification
. Use at your own risk.