1

I know in Swift it's possible to make use of #available and objective-c doesn't support that.

Is there still a way to make an os x app which can be run on 10.11 but also supports the NSTouchbar (which starts from 10.12)?

ChiellieNL
  • 103
  • 1
  • 8

1 Answers1

4

#available and friends in Swift are a simplification of (and improvement on) the more complex ways of dealing with new features and backward compatibility in ObjC. If you're using ObjC, there isn't a direct equivalent to #available, so you have to fall back to those old ways. Apple's docs on such can be found in the SDK Compatibility Guide. The gist:

  1. Build your project using the latest Xcode 8.x / macOS 10.12.x (or later) SDK.

  2. Set your project's Base SDK to macOS 10.12 (or later), and its Minimum Deployment Target to 10.11.

  3. This makes the AppKit classes/methods you're looking for "weak linked", so you can check for their presence at run time. For example:

    if ([NSTouchBar class]) {
        self.touchBar = [[NSTouchBar alloc] init];
        self.touchBar.delegate = self;
        self.touchBar.defaultItemIdentifiers = @[ /*...*/ ];
        //...
    }
    

    In macOS versions predating touch bar support, [NSTouchBar class] returns nil, so none of the touch bar usage happens. In versions with touch bar support, your if body executes.

rickster
  • 124,678
  • 26
  • 272
  • 326
  • Code should implement `makeTouchBar` instead of setting `touchBar` directly; then there's no need for the check and it won't be using extra memory if no Touch Bar exists. – Wevah Jan 11 '17 at 09:19
  • This isn't about testing whether the Touch Bar *hardware* exists; it's checking for the API needed to use it. The body of this `if` executes on any macOS 10.2.2 machine, not just new MacBooks. If you're deploying to both 10.2.2 and 10.11, you need to check for the presence of any new API before calling it. – rickster Jan 11 '17 at 15:58
  • Yeah, but you don't need to wrap anything if you're using -makeTouchBar unless you're checking for it (the classes/methods, not the hardware) outside of setup. – Wevah Jan 11 '17 at 16:00
  • Either way, the first part of my initial comment is what's recommended; that way, even on 10.12.2, if the Mac has no touch bar, no NSTouchBar is even allocated. There was a tweet about it from an Apple engineer, but I can't find it now. :/ – Wevah Jan 11 '17 at 16:03
  • (You still need to make sure `NSTouchBar` exists if you're using it outside of setup/delegation, for example, if you need to update a Touch Bar item based on model state or something, so your answer is still valid.) – Wevah Jan 11 '17 at 16:04
  • Yep, it works! (for now I've just created a TouchBar within interface builder and linked it to a `@property (weak) NSTouchBar* touchBar` within the ViewController). Still got to be careful though, first times the app crashed because I used other code that was new in 10.12 (like `[NSLocale currentLocale].languageCode`) which I wasn't aware of. Thanks! – ChiellieNL Jan 11 '17 at 21:06