Learned the hard way: #available doesn't help when the symbol isn't in the SDK you compile with
Ran into this adopting an iOS 27 beta API (SCSensitivityAnalysis.detectedTypes) in a package that still has to build on stable Xcode.
First attempt was the obvious one:
if #available(iOS 27, *) {
let types = analysis.detectedTypes
}
Builds fine on the Xcode 27 beta, fails on 26.5. #available is a runtime check, the compiler still needs the symbol to exist at build time. Older
SDK, no symbol, no build.
What works is gating at compile time as well:
#if compiler(>=6.4)
if #available(iOS 27, *) {
// detectedTypes code here
}
#endif
#if compiler tracks the Swift version that ships with Xcode, so >=6.4 is a proxy for "the iOS 27 SDK is present". canImport doesn't help in this
case because the framework has existed since iOS 17, only the property is new.
Real-world usage if you want to see the pattern in context: https://github.com/SardorbekR/SafeMediaKit (the detectedTypes mapping is isolated inone file exactly because of this gating)
Is there a cleaner way to gate on symbol existence? compiler(>=6.4) works but feels blunt, since what I actually mean is "this SDK has this property" and the Swift version is just the best proxy I found
Posted Jul 29, 2026, 1:00 PM UTC