SE-0075 introduces a build configuration import test. This test enables you to check whether you can import certain modules, like
QuartzCore, enabling you to write cross-platform code that compiles regardless of destination. You can test for common scenarios like: “Am I on an Apple platform?” or “Am I on an UIKit-supporting iOS-like platform such as iOS or tvOS”.
All bets for the specificity of the latter check are off as of WWDC this year, but the configuration test should allow you to test “Am I on a Unified UI Platform”, whatever that turns out to be, so long as there’s a common module, such as
UXKit shared across platforms.
It might help to think of this as module-wide protocol conformance. If the platform conforms to a module and can import it, then the code can be built with access to all its APIs.
#if canImport(UIKit) // UIKit-based code #elseif canImport(Cocoa) // OSX code #elseif // Workaround/text, whatever #endif
Before adopting this proposal, testing
!(os(Linux) was too brittle. It assumed a binary system of Apple-systems and Linux (and there are many more Swift destinations now). Enumerating every current Apple or non-Apple platform available at a given time is simply not future-proof. Tying the build configuration to a module, establishes a link between available APIs and the ability to import the API’s parent module.
This one turned out to be a really hard one to implement and all the credit goes to Robert Widmann, Rintaro Ishizaki, Ben Cohen, and Jordan Rose (and anyone else who pitched in) for turning an idea into a reality. This was also one of the proposals that gave rise to the new “implement first, propose second” policy that currently governs Swift Evolution. If you want to thank anyone it’s them, not me.
SE-0190 wasn’t as complicated, but it’s still Graydon Hoare who did all the work on making this happen while I was out of commission this past autumn. In a nutshell, you can use a new platform condition
targetEnvironment to test whether your code is running on a simulator and exclude code you know won’t work there.
Until now, you had to use brittle solutions like
(arch(i386) || arch(x86_64)) && (!os(macOS)) to check for simulator deployment and
(arch(i386) || arch(x86_64)) && os(iOS) specifically for the iOS simulator. Now you can use
#if targetEnvironment(simulator)instead (or its inverse, using
!). The design is intentionally wordy to allow additional environment tests to be added at some future date.
So thanks to everyone who made this happen, especially when I could not.