Search code examples
macoscalayernsview

Why would layer be nil, after wantsLayer=true?


I made a new OS X project in Xcode 8, added a single (image) view. I dragged it to the default ViewController source, to add an @IBOutlet (named "image"). Then in viewDidLoad(), I added:

image.wantsLayer = true
image.layer!.cornerRadius = 10

About half the time, it works fine, and about half the time, it dies with:

fatal error: unexpectedly found nil while unwrapping an Optional value

while pointing at the second line, and in the debugger:

(lldb) po image.wantsLayer
true

(lldb) po image.layer
nil

Is setting wantsLayer supposed to create a layer immediately? The documentation seems to suggest this, but I can't find a statement that makes this explicit.

I've seen a lot of code, like this, which makes an NSView do:

self.wantsLayer = true
self.layer!.backgroundColor = ...

so it seems like it ought to. Why would layer be nil, after setting wantsLayer? Am I supposed to set layer myself, even if I ask for wantsLayer?


Solution

  • For layer backed views on OS X it is not recommended to interact with the layer object directly. The layer is owned by AppKit. That is described in a few more words here as well: https://www.objc.io/issues/14-mac/appkit-for-uikit-developers/

    Now, if you subclass your view and return YES/true on wantsUpdateLayer property of your NSView, you can update the layer in updateLayer. Note this will lead to AppKit not calling drawRect anymore.