2

While here Apple states that the Swift available flag should be applied also in objc, it's not working for me. What am I doing wrong?


I've got following declarations in Swift files:

@objc protocol Readable: AnyObject {...}

@available(iOS 10.3, *)
@objc class Reader: NSObject, Readable {...}

So let's check if it produces an error when I try to initialize it in pre-ios-10 project without version check. If I write following code in Swift:

let tmp = Reader()

it returns an error:

'Reader' is only available on iOS 10.3 or newer

What is expected.


However if I write following code in objc:

// if (@available(iOS 10.3, *)) { // commeted out to test if it succeeds without version check
    Reader *tmp = [[Reader alloc] init];
// }

The build is finished without any error, while I'd expect the same error as in Swift.


I've tried to mark the class with:

  • @available(iOS 11, *)
  • @available(iOS, introduced: 10.3)

Neither of these works (produces an error) in objc. Any help, please?

Nat
  • 12,032
  • 9
  • 56
  • 103

1 Answers1

1

Objective-C has had __attribute__((availability)) for longer than it has had @available. To make it work, the Objective-C compiler weakly links symbols that are not available on the deployment target. This means that compiling always succeeds, and starting your app succeeds, but the symbol will be NULL at runtime if it is not available.

Depending on what it is, you'll get more or less graceful degradation when you try to use it:

  • calling a weakly-linked function that is missing is going to crash
  • reading or writing to a global variable that is missing is going to crash
  • using a class that is missing will be a no-op and all methods are going to return zero

The old way of testing whether a symbol is found at runtime is just to compare it to NULL:

NS_AVAILABLE_MAC(...) @interface Foo @end
int bar NS_AVAILABLE_MAC(...);
int baz(int frob) NS_AVAILABLE_MAC(...);

if ([Foo class]) { /* Foo is available */ }
if (&bar) { /* bar is available */ }
if (&baz) { /* baz is available */ }

In your case:

Reader *tmp = [[Reader alloc] init];

tmp will be nil, because that would be the same as [[nil alloc] init].

The @available directive has only relatively recently been added to Objective-C. It's now possible to use @available in Objective-C in the same way that you use #available in Swift. However, to preserve backwards compatibility, it possibly never will be a compile-time error (at default error levels) to try to use a symbol that might not be available on the deployment target in Objective-C.

zneak
  • 134,922
  • 42
  • 253
  • 328
  • Shouldn't it at least produce a warning..? Because for me it doesn't in objc. – Nat Jan 15 '19 at 22:08
  • @Vive, check if your compiler invocation includes the `-Wunguarded-availability` or `-Wunguarded-availability-new` warning flag. You should be able to find the setting that controls it in your project's Build Settings, section Apple Clang - Warnings - All languages, as "Unguarded availability". – zneak Jan 15 '19 at 22:12
  • The [`-Wungarded-availability-new` flag](https://reviews.llvm.org/D34264) will only warn about unguarded APIs introduced in macOS >= 10.13, iOS >= 11, watchOS >= 4 and tvOS >= 11 (to avoid spamming warnings for older code). – zneak Jan 15 '19 at 22:16
  • 1
    I already checked that.. and I was wrong! I had `unguarded availability` set to `YES` while it should be `YES (all versions)`. Issues fixed, thank you! – Nat Jan 15 '19 at 22:20
  • @Vive do you mean that with setting `YES (all versions)` you now have build error on the Objective-C code when instantiating `Reader` below iOS 10.3 ? – Niko Nov 03 '20 at 18:52
  • @Niko You are aware the last activity in this thread was almost 2 years ago? Swift did change a lot, objc-swift interoperability and compiler as well, so if you need it, you're free to test it. From above conversation, I understand it displayed the error. Do you have an issue with implementing this solution? If so, ask direct question. – Nat Nov 03 '20 at 22:46
  • @Vive thank you for having taken the time reply, I saw this was from 2 years ago, but made a mistake not using past tense in my question, sorry about that. I know things move fast, but some don't that is why I wanted to know what was the end result on this – Niko Nov 03 '20 at 23:03