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 Value | Name | Environment Variable | Default |
|---|---|---|---|
ios | iOS/iPadOS/Mac Catalyst | IPHONEOS_DEPLOYMENT_TARGET | 10.0 |
macos | macOS | MACOSX_DEPLOYMENT_TARGET | 10.12 |
tvos | tvOS | TVOS_DEPLOYMENT_TARGET | 10.0 |
visionos | visionOS | XROS_DEPLOYMENT_TARGET | 1.0 |
watchos | watchOS | WATCHOS_DEPLOYMENT_TARGET | 5.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:
-
Check statically that you’re compiling for a version where the API is available, e.g. by checking the
*_DEPLOYMENT_TARGETvariables in a build script or atconsttime. -
Check at runtime that a class, method or symbol is available, using e.g.
AnyClass::get,respondsToSelectoror 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.
}