Compiler directives in SwiftUI for platform-specific attributes

I'm building a universal application with SwiftUI that has an iOS app and Share Extension as well as a macOS app and Share Extension.

There's a few places where I'm using SwiftUI attributes that are iOS-specific (example a NavigationView that has a StackNavigationViewStyle attribute) and need to provide an alternative when running on macOS.

My question is: How do I ensure that these attributes that are only available for one platform don't cause build issues for the other platform? I've tried using the #if os(iOS) compiler directive, but then I get a build error saying "Unexpected platform condition (expected 'os' 'arch' or 'swift')" when doing something like this:

Code Block swift
NavigationView {
...
}
        #if os(iOS)
.navigationViewStyle(StackNavigationViewStyle())
        #endif



  • I believe this feature was added in Swift 5.4 Swift by sundell has an article about it.

Add a Comment

Accepted Reply

In #if compiler directive in Swift, you need to enclosed valid statements.

As you can see, .navigationViewStyle(StackNavigationViewStyle()) is not a valid statement.

You may need to write something like this:
Code Block
#if os(iOS)
var body: some View {
NavigationView{
...
}
.navigationViewStyle(StackNavigationViewStyle())
}
#else
var body: some View {
NavigationView{
...
}
.navigationViewStyle(DoubleColumnNavigationViewStyle())
}
#endif


Or this:
Code Block
var body: some View {
let navView = NavigationView{
...
}
#if os(iOS)
return navView
.navigationViewStyle(StackNavigationViewStyle())
#else
return navView
.navigationViewStyle(DoubleColumnNavigationViewStyle())
#endif
}


Replies

In #if compiler directive in Swift, you need to enclosed valid statements.

As you can see, .navigationViewStyle(StackNavigationViewStyle()) is not a valid statement.

You may need to write something like this:
Code Block
#if os(iOS)
var body: some View {
NavigationView{
...
}
.navigationViewStyle(StackNavigationViewStyle())
}
#else
var body: some View {
NavigationView{
...
}
.navigationViewStyle(DoubleColumnNavigationViewStyle())
}
#endif


Or this:
Code Block
var body: some View {
let navView = NavigationView{
...
}
#if os(iOS)
return navView
.navigationViewStyle(StackNavigationViewStyle())
#else
return navView
.navigationViewStyle(DoubleColumnNavigationViewStyle())
#endif
}


I was hoping there would be some other way other than defining another body var. Thanks for the reply — I'll give abstracting out the views a try and then using the second example!
If you don't want to duplicate body, you can make use of a View extension: https://stackoverflow.com/a/62099616/64949