Search code examples
nsviewappkitnsviewcontrollerviewdidappear

How to implement `viewDidAppear` without NSViewController?


There is a method in NSViewController called viewDidAppear. The docs say:

This method is called after the completion of any drawing and animations involved in the initial appearance of the view.

If there were no NSViewController class, and you were manually managing your tree of NSView objects, how could you implement something similar? I don't see a way to subscribe to an "appeared" event or notification about an NSView.


Solution

  • I don't see a way to subscribe to an "appeared" event or notification about an NSView.

    There isn't one because if your view is not being managed by an NSViewController then it's not participating in the NSViewController lifecycle.

    If you want to manually track when your view "appears", then you'll need to sort of decide what "appears" means in the context of your use-case.

    For initial appearance, you'll want to look at:

    • NSView.viewDidMoveToWindow
    • NSView.viewDidMoveToSuperview

    For transient appearance, you'll want to look at:

    • NSView.viewDidHide
    • NSView.viewDidUnhide

    You might also want to just query the appropriate properties:

    • NSView.hidden
    • NSView.hiddenOrHasHiddenAncestor

    If you care about the parent window's "appearance", then consider:

    • The various NSWindow...Notification notifications because there are a lot of them that relate to a window's visibility or "hiddeness".

    If you're showing a view in a sheet or some other sort of modal container, then I'd recommend first implementing it with NSViewController and then setting a breakpoint on viewDidAppear. The backtrace will show you which methods were previously called and you can just pick one high enough up the call stack for your use-case.

    I make extensive use of NSViews without view controllers in some of my applications. In most cases, I just setup the view in the initializer because it's very rare that I would create a view but not present right away.

    If a view is doing something like receiving notifications, running animations or continuously redrawing and you want to start or stop those actions depending on the view's visibility, then just override the appropriate NSView method above.

    However, I've found that if I see myself using that pattern, then there's a good chance the view is doing more than it should be doing and I pull that code out into some other class that I can explicitly start and stop independently from the view's visibility. YMMV...