Is there a way to conditionally use @StateObject while targeting iOS 13?

Viewed 2082

I have a SwiftUI app that is targeting iOS 13 and higher. I would like to conditionally use the @StateObject property wrapper if I am running on iOS 14, as it would fix so many bugs I've had to workaround on iOS 13.

Is there any way to conditionally do this via #ifdef or #if available(iOS 14, *) calls or similar? I'm happy to have a completely separate implementation of a given view for iOS 14.

I've tried this but it of course doesn't compile.

struct MyView: View {
    if #available(iOS 14, *) {
        @StateObject var viewModel: ViewModel()
    } else {
        @ObservedObject var viewModel: ViewModel
    }
2 Answers

This can be done using the @available attribute like so:

class ViewModel: ObservableObject {}

@available(iOS 14, *)
struct FourteenView: View {
    @StateObject var viewModel = ViewModel()
    var body: some View {
        Text("iOS 14")
    }
}

struct ThirteenView: View {
    @ObservedObject var viewModel = ViewModel()
    var body: some View {
        Text("iOS 13")
    }
}

struct ContentView: View {
    var body: some View {
        if #available(iOS 14, *) {
            AnyView(FourteenView())
        } else {
            ThirteenView()
        }
    }
}

This only works in Xcode 12 of course. I'm using 12.0 beta 3 (12A8169g).

The AnyView() in the ContentView is because using if #available(iOS 14, *) in a @ViewBuilder doesn't seem to work properly. See this Apple Developer Forum thread.

Related