iosswiftxcodemacosswiftui

How do I conditionally compile swift based on swift version and target SDK?


I want to be able to conditionally compile blocks of swift code based on the version of the swift language and the version of the target SDK used by the build system. I have no control over the user's build system. I notice on mine the following command line arguments are passed to the compiler by Xcode: -swift-version 5 and -target-sdk-version 14.2. So I was hoping for something like the following, but I can't figure it out.

#if swift-version >= 5
    ...swift code...
#else
    ...old approach...
#endif


#if target-sdk-version >= 14.2
    ...swift code...
    ...perhaps using #available if deployment sdk is older...
#else
    ...old approach...
#endif

Here's a simple example. Suppose I have a SwiftUI scene that I want to apply the modifier .restorationBehavior(.disabled) But that's only available in the SDK 15.0 and later. What should the source code look like if I want just the default behavior if one is building against an older SDK?

Here's one futile attempt to make a Scene modifier that can just be used like this .pleaseDisableRestoration()

extension Scene {
@available(swift, introduced: 6.0)
    func pleaseDisableRestoration() -> some Scene {
        if #available(macOS 14, *) { //run time check
            return self.restorationBehavior(.disabled)
        }else{
            return self
        }
    }

@available(swift, obsoleted: 6.0)
    func pleaseDisableRestoration() -> some Scene {
        return self
    }
}

It fails for two reasons: (1) the self.restorationBehavior modifier will not compile if I'm using Swift 5, even though the declaration is marked for Swift 6 and later; and (2) the reuse of the declaration pleaseDisableRestoration won't work even though there is no overlap in the Swift versions they apply to.

As DonMag points out I can use #if swift(>=6.0) for half the problem. Unfortunately, the important case is the SDK level. But the example above rewritten using...

@available(macOS, introduced: 15.0)
...
@available(macOS, obsoleted: 15.0)
...

...fails in the same way.


Solution

  • @timbre's answer makes many good points and is worth an up-vote. But it didn't answer exactly what I needed. So here's what I came up with.

    See this article for how I came up with 6.0 corresponding to target SDK macOS 15

    #if swift(>=5.0)
        ...swift code...
    #else
        ...old approach...
    #endif
    
    
    #if canImport(SwiftUI, _version: "6.0") //hack to test for macOS 15 target sdk
        ...swift code...
        ...perhaps using #available if deployment sdk is older...
    #else
        ...old approach...
    #endif