available

Macro available 

Source
macro_rules! available {
    (
        // Returns `false` on unspecified platforms.
        $(
            $os:ident $(= $major:literal $(. $minor:literal $(. $patch:literal)?)?)?
        ),* $(,)?
    ) => { ... };
    (
        // Returns `true` on unspecified platforms because of the trailing `..`.
        $(
            $os:ident $(= $major:literal $(. $minor:literal $(. $patch:literal)?)?)?,
        )*
        ..
    ) => { ... };
}
Expand description

Check if APIs from the given operating system versions are available.

Apple adds new APIs with new OS releases, and as a developer, you often want to use those to give your users the best behaviour, while still supporting older OS versions that don’t have those APIs (instead of crashing e.g. because of an undefined selector).

This macro allows you to conditionally execute code depending on if the current OS version is higher than or equal to the version given in the macro.

If no version is specified for a certain OS, the API will be assumed to be unavailable there. This default can be changed by adding a trailing .. to the macro invocation.

This is very similar to @available in Objective-C and #available in Swift, see Apple’s documentation. Another great introduction to availability can be found in here.

§Operating systems

The operating system names this macro accepts, the standard environment variables that you use to raise the deployment target (the minimum supported OS version) and the current default versions are all summarized in the table below.

OS ValueNameEnvironment VariableDefault
iosiOS/iPadOS/Mac CatalystIPHONEOS_DEPLOYMENT_TARGET10.0
macosmacOSMACOSX_DEPLOYMENT_TARGET10.12
tvostvOSTVOS_DEPLOYMENT_TARGET10.0
visionosvisionOSXROS_DEPLOYMENT_TARGET1.0
watchoswatchOSWATCHOS_DEPLOYMENT_TARGET5.0

The default version is the same as that of rustc itself.

§Optimizations

This macro will statically be set to true when the deployment target is high enough.

If a runtime check is deemed necessary, the version lookup will be cached.

§Alternatives

Instead of checking the version at runtime, you could do one of the following instead:

  1. Check statically that you’re compiling for a version where the API is available, e.g. by checking the *_DEPLOYMENT_TARGET variables in a build script or at const time.

  2. Check at runtime that a class, method or symbol is available, using e.g. AnyClass::get, respondsToSelector or weak linking.

§Examples

Use the effectiveAppearance API that was added in macOS 10.14.

use objc2_app_kit::{NSApplication, NSAppearance, NSAppearanceNameAqua};
use objc2::available;

let appearance = if available!(macos = 10.14) {
    // Dark mode and `effectiveAppearance` was added in macOS 10.14.
    NSApplication::sharedApplication(mtm).effectiveAppearance()
} else {
    // Fall back to `NSAppearanceNameAqua` on macOS 10.13 and below.
    NSAppearance::appearanceNamed(NSAppearanceNameAqua).unwrap()
};

Use an API added in Xcode 16.0 SDKs.

We use .. here in case Apple adds a new operating system in the future, then we probably also want the branch to be taken there.

use objc2::available;

if available!(ios = 18.0, macos = 15.0, tvos = 18.0, visionos = 2.0, watchos = 11.0, ..) {
    // Use some recent API here.
}

Set the wantsExtendedDynamicRangeContent property, which is available since iOS 16.0, macOS 10.11 and visionOS 1.0, but is not available on tvOS and watchOS.

use objc2::available;

if available!(ios = 16.0, macos = 10.11, visionos = 1.0) {
    layer.setWantsExtendedDynamicRangeContent(true);
}

Work around problems in a specific range of versions (an example of this in the real world can be seen in #662).

use objc2::available;

if available!(macos = 15.0) && !available!(macos = 15.1) {
    // Do something on macOS 15.0 and 15.0.1.
} else {
    // Do something else on all other versions.
}