9

As of 2018, what is the correct way to create a custom control with AppKit/Cocoa?

The traditional technique has been to subclass NSControl and/or NSCell for the type of custom control you're implementing. (Such as an NSButton that does custom drawing.)

However, in WWDC 2014-204 Apple stated that NSCell is on its way to "Formal Deprecation". In WWDC 2012-217, Apple suggests subclassing NSView and taking advantage of layer-backing and layer properties to draw a simple button.

If you subclass NSView to create a custom control (such as a "better button") then you lose a lot of functionality that NSControl offers, such as pre-wired action and target properties, mouse-tracking, keyboard activation and probably a bunch of other things I'm not even aware of.

If you subclass NSControl, or even NSButton, what is the correct way to take over all of the drawing? Apple's Programming Guide has not been updated regarding this. In particular, can an NSButton subclass just override all the draw... methods from itself and NSCell and then just do what it wants to do in updateLayer? Is there any guarantee that the existing NSButton/NSButtonCell drawing code won't still do any drawing?

What if you wanted to build a button with a custom background but still uses a string-based title or attributedTitle? NSButton offers this but how does the title drawing interact with updateLayer?

My use-case is to create a custom button that offer more visual states and more visual designs than a traditional NSButton. Using a layer-backed NSView and updateLayer makes implementing all of the different states a breeze, but I'd prefer to subclass NSControl or even NSButton so that I also retain all of the functionality that those classes already offer.

Edit 1: Changed wording based on comments below to more accurately reflect the current deprecation state of NSCell.

kennyc
  • 5,490
  • 5
  • 34
  • 57
  • Where are you hearing that `NSCell` is deprecated? The release notes have been talking about their plans to _eventually_ deprecate it for years, but AFAIK they haven't pulled the trigger on that yet. – Charles Srstka May 20 '18 at 16:11
  • 1
    `NSCell` is _not_ deprecated as of 10.13. `NSCell` has been deprecated for use in `NSTableView` et. al. for years now, with the transition to `NSView` based tables and collection views. This is where you probably heard that you shouldn't use cell objects. `NSCell` is used by `NSControl` and every core Cocoa control (`NSButton`, `NSSegmentControl`, `NSDatePicker`, `NSSlider`, ...). So for now, `NSCell` is alive and well inside the `NSControl` family. – James Bucanek May 20 '18 at 16:29
  • James, if you look at the bottom of `NSControl.h` you'll see that most of the cell related properties and methods have been moved into a category called "NSDeprecated". As well, in WWDC 2014-204, Apple makes a *really* strong statement that `NSCell` (and in particular when it relates to `NSControl`) is on its way to formal deprecation. That was four years ago. I agree that NSCell might not be formally deprecated today, but it's about as close as it can get. – kennyc May 20 '18 at 18:26
  • @JamesBucanek The cell based table view is not deprecated. [NSTableView](https://developer.apple.com/documentation/appkit/nstableview?language=objc) "You can still use NSCell objects for each row and column item if you prefer." – Willeke May 20 '18 at 22:43
  • I have no doubts that Apple would like to move away from `NSCell`, but the reality is that every `NSControl` subclass is still built on top of `NSCell` and Apple has yet to provide a functional alternative. In the case of `NSTable`, Apple *has* provided an `NSView` alternative that we can use today. So in the grand order of things, I feel that `NSCell` for tables is "more deprecated" than `NSCell` for `NSControl`. – James Bucanek May 20 '18 at 23:30

0 Answers0