[swift-users] Check deployment target at runtime or compile time

Ole Begemann ole at oleb.net
Wed Feb 15 13:11:24 CST 2017

In macOS 10.12 and iOS 10.0, class properties were introduced to 
Objective-C [1]. I noticed that the Objective-C runtime treats class 
properties differently based on the deployment target. Example:

     // MyClass is an Objective-C class that has a class property
     let metaclass = object_getClass(MyClass.self)
     var count: UInt32 = 0
     let properties = class_copyPropertyList(metaclass, &count)
     // Work with properties
     // Deallocate properties

When the deployment target is macOS 10.12, passing a metaclass to 
copyPropertyList() returns the class properties, but it returns an empty 
list on a lower deployment target.

I'd like to perform a check (either at runtime or compile time) which of 
these behaviors I'll get.

I didn't find a way to perform a compile-time check in Swift against the 
deployment target; if #available() checks against the SDK the code is 
linked against. Likewise, the usual runtime check using 
ProcessInfo().isOperatingSystemAtLeast() doesn't check against the 
deployment target.

The best I came up with is this:

  Returns `true` if the current deployment target is at least the 
specified version that corresponds to the current platform.

  The arguments must be passed in the form of the `__MAC_XX_X`, 
`__IPHONE_XX_X`, etc. constants defined in Availability.h.
public func isDeploymentTargetAtLeast(
     macOS macOSVersion: Int32, iOS iOSVersion: Int32,
     tvOS tvOSVersion: Int32, watchOS watchOSVersion: Int32) -> Bool {

     #if os(macOS)
         return __MAC_OS_X_VERSION_MIN_REQUIRED >= macOSVersion
     #elseif os(iOS)
         return __IPHONE_OS_VERSION_MIN_REQUIRED >= iOSVersion
     #elseif os(tvOS)
         return __TV_OS_VERSION_MIN_REQUIRED >= tvOSVersion
     #elseif os(watchOS)
         return __WATCH_OS_VERSION_MIN_REQUIRED >= watchOSVersion
         return false

For example, to test if the current deployment target is at least macOS 
10.12, iOS 10.0, tvOS 10.0, or watchOS 3.0:

guard isDeploymentTargetAtLeast(
     macOS: __MAC_10_12, iOS: __IPHONE_10_0,
     tvOS: __TVOS_10_0, watchOS: __WATCHOS_3_0) else {

     // Deployment target is lower

Is this correct? Is there a better way to do this?

[1]: http://useyourloaf.com/blog/objective-c-class-properties/

More information about the swift-users mailing list