Objective-C API availability checks give wrong results

On old versions of macOS I get failed tests which turn out fine on my own machine. It seems that the macOS environments on travis CI give wrong information about ObjC API availabilities. Here is a simple ObjC program to demonstrate the issue: https://github.com/patr0nus/travis_objc_if_available/blob/63a928b63ae7bf9aed1dda6456da885887df3565/objc.m

On travis I compiled this program on 10.14 and ran it on 10.11-10.13. Here is the results:

https://travis-ci.com/patr0nus/travis_objc_if_available/jobs/259338793

https://travis-ci.com/patr0nus/travis_objc_if_available/jobs/259338794

https://travis-ci.com/patr0nus/travis_objc_if_available/jobs/259338795

macOS 10.11-10.13 all claim that the 10.14 APIs are available but they are actually not. This break tests that depend on the API availability checking.

According to https://developer.apple.com/documentation/swift/objective-c_and_c_code_customization/marking_api_availability_in_objective-c, @available checks availability at compile time, you need to use #available to check it at runtime.

It turns out it IS a runtime/compile-time thing, but not that simple.

if (@available(...)) in Objective-C should be a runtime check, just like its swift equivalence if #available(...). But the compiler optimizes the else branch out in release builds, because it assumes the program will only be deployed on the same version of macOS where the compilation happens.

To force the compiler to do the check at runtime one must tell the compiler that the program could run on an older macOS by setting the MACOSX_DEPLOYMENT_TARGET environment variable.

1 Like