> On 15 Feb 2017, at 20:40, Greg Parker <[email protected]> wrote:
>
>> On Feb 15, 2017, at 11:11 AM, Ole Begemann via swift-users
>> <[email protected]> wrote:
>>
>> 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.
>
> That's right. The Objective-C runtime was written with the expectation that
> class properties would be added someday, but that code was buggy. On macOS
> 10.10 and iOS 8.x and older if libobjc sees a class property then it may
> crash. The fix was for clang and swiftc to leave class properties out of the
> ObjC metadata when compiling for those deployment targets.
>
> macOS 10.11 and iOS 9.x deployment targets are both safe. (Class properties
> still did not exist then. Instead the bug that nobody had seen yet was
> unknowingly fixed when the code was rewritten for an unrelated optimization.)
Thank you, Greg. I only tested with 10.12 and 10.10, so I hadn't noticed that
it would already work with 10.11.
> Note that class property visibility depends on the deployment target used to
> compile that class's implementation. It is possible to see class properties
> from some classes but not others if the classes come from different
> executables with different deployment targets.
>
>> 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
>> #else
>> return false
>> #endif
>> }
>>
>> 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?
>
> That code ought to work, assuming that the implementation of
> isDeploymentTargetAtLeast() and the implementations of the interrogated
> classes are in the same executable, or are all in executables compiled with
> the same deployment target.
_______________________________________________
swift-users mailing list
[email protected]
https://lists.swift.org/mailman/listinfo/swift-users