iosswiftswiftuiasync-awaittask

Call async function in .sheet or .fullScreenCover SwiftUI


Using RevenueCat and checking the users subscription status. If Subscribed or not will determine the view shown in a fullScreenCover

Only as the call to check status is async I have to call with await and wrap in a Task{} which is not possible inside a fullScreenCover.

How to call a async function in a fullScreenCover

.fullScreenCover(isPresented: $subscriptionIsExpanded){
                Task {
                if await StoreManager.isPremiumSubscriber() {
                          ActiveSubscription()
                        }
                   else{
                    PaywallView(displayCloseButton: true)
                }
            }
     }

Task{} gives error: Static method 'buildExpression' requires that 'Task<(), Never>' conform to 'View'


Solution

  • You could try a different approach to call your async function inside the .fullScreenCover or .sheet.

    For example using a simple @State private var isDone: Bool? to display the appropriate View as a result of your async task.

    Example code:

    struct ContentView: View {
        @State private var subscriptionIsExpanded = false
        @State private var isDone: Bool?
        
        var body: some View {
            VStack {
                Button("Click me") {
                    subscriptionIsExpanded = true
                }.buttonStyle(.bordered)
            }
    //        .sheet(isPresented: $subscriptionIsExpanded, onDismiss: { isDone = nil }) {
    //            sheetView()
    //        }
            .fullScreenCover(isPresented: $subscriptionIsExpanded) {
                sheetView()
            }
        }
        
        @ViewBuilder
        func sheetView() -> some View {
            VStack {
                HStack {
                    Button("Dismiss") {
                        isDone = nil
                        subscriptionIsExpanded = false
                    }
                    Spacer()
                }
                Spacer()
                switch isDone {
                    case true: Text("ActiveSubscription") // ActiveSubscription()
                    case false: Text("PaywallView") // PaywallView(displayCloseButton: true)
                    default: ProgressView()
                }
               Spacer()
            }
            .task {
                isDone = await isPremiumSubscriber()
                // isDone = await StoreManager.isPremiumSubscriber()
            }
        }
        
        // for testing, StoreManager.isPremiumSubscriber()
        func isPremiumSubscriber() async -> Bool {
            try! await Task.sleep(for: .seconds(2))
            return Int.random(in: 0...1) < 1
        }
        
    }