-[NSView (un)lockFocus] deprecated, what to use instead?

I am hitting major road blocks in migrating one of my Obj-C-Cocoa applications away from -[NSView (un)lockFocus] and -[NSBitmapImageRep initWithFocusedViewRect:].

In a transcript of a presentation on WWDC2018 I read:

With our changes to layer backing, there's a few patterns I want to call out that aren't going to work in macOS 10.14 anymore. If you're using NSView lockFocus and unlockFocus, or trying to access the window's graphics contents directly, there's a better way of doing that. You should just subclass NSView and implement draw rect. ...

Of course, we all implemented -[NSView drawRect:] for decades now. The big question is, how can we do incremental (additional, event driven) drawing in our views, without redrawing the whole view hierarchy. This is the use case of -(un)lockFocus, and especially when drawing of the base view is computational expensive. Wo would have thought that people use -(un)lockFocus for regular drawing of the NSView hierarchy.

I tried to get away with CALayer, only to find out after two days experimenting with it, that a sublayer can only be drawn if the (expensive) main layer has been drawn before —> dead end road.

Now I am going to implement a context dependent -[NSView drawRect:]. Based on a respective instance variable, either of the (expensive) base presentation of the view or the simple additions are drawn. Is it that what Apple meant by … just subclass NSView and implement draw rect?

From the point of view of object oriented programming, using switch() in methods to change the behaviour of the object is ugly - to say the least. Any better options?

Ugly or not, in any case, I don’t want to redraw the whole view hierarchy only for moving a crosshairs in a diagram.

My actual use case is:

This application draws into a custom diagram NSView electrochemical measurement curves which may consist of a few thousands up to millions of data points. The diagram view provides a facility for moving crosshairs and other pointing aids over the displayed curves, by dragging/rolling with the mouse or the touch pad, or by moving it point by point with the cursor keys.

Diagram generation is computational expensive and it must not occur only because the crosshairs should be moved to the next data point.

So for navigating the crosshairs (and other pointing aids), a respective method locks the focus of said view, restores the background from a cache, caches the background below the new position of the crosshairs using -[NSBitmapImageRep initWithFocusedViewRect:], draws the crosshairs and finally unlocks the focus.

All this does not work anymore since 10.14.

Replies

I'm sad that there is not a reply to this after a whole year. It seems this is an obvious use case and I am running into a similar situation.

You can move your crosshairs to a separate CALayer or to multiple one, so you don't have to redraw anything but just changed the coordinate of such layers. No need to redraw the diagram each time. Or use CATiledLayer or something similar.