Why won't SwiftUI view update based on async task results (new to SwiftUI)

See the following View and the supporting model. The view is not updating with the search results generated through the .task beerViewVM.search call.

The search is working fine as the print statements (see below) after the await each print the correct information. However, the view is not updated with these values.

I’m still learning managing state so I imagine I’m overlooking the obvious. I would appreciate any guidance. Thanks — jay

//
//  BeerView.swift
//

import SwiftUI

struct BeerView: View {
    
    @StateObject private var beerViewVM = BeerDetailViewModel()
    
    let bid: Int
    
    var body: some View {
        VStack {
            VStack (alignment: .leading) {
                Text(beerViewVM.response?.beer.beerName ?? "no name")
                    .font(.largeTitle)
                    .fontWeight(.bold)
                Text(beerViewVM.response?.beer.brewery.breweryName ?? "no brewery")
                    .padding(.bottom)
                    .foregroundColor(.secondary)
                HStack {
                    InfoCellView(text: String(format: "%.1f", beerViewVM.response?.beer.ratingScore ?? 0), label: "rating")
                    InfoCellView(text: String(format: "%.1f", beerViewVM.response?.beer.beerAbv ?? 0), label: "abv")
                    InfoCellView(text: String(format: "%.1f", beerViewVM.response?.beer.beerIbu ?? 0), label: "ibu")
                }
                .padding(.bottom)
                
                Text(beerViewVM.response?.beer.beerDescription ?? "no rating")
                
            }
            .padding()
            Spacer()
        }
        .task {
            await beerViewVM.search(bid: bid)
                        print(beerViewVM.response!)
                        print("-----------")
                        print(beerViewVM.response!.beer.bid)
                        print(beerViewVM.response!.beer.beerName)
                        print("\(beerViewVM.response!.beer.ratingScore)")
        }
    }
    
}

struct InfoCellView: View {
    
    let text: String
    let label: String
    
    var body: some View {
        
        VStack(alignment: .leading) {
            Text(text)
                .font(.title2)
                .fontWeight(.bold)
            Text(label)
                .font(.caption)
                .foregroundColor(.secondary)
        }
        .frame(width: 50.0)
    }
}



//
//  BeerDetailViewModel.swift
//

import Foundation

@MainActor
class BeerDetailViewModel: ObservableObject {
    
    @Published var response: ResponseBeer?
    
    func search(bid: Int) async {
        do {
            let response = try await Webservice().getBeerInfo(bid: bid)
            self.response = response
        } catch {
            print(error)
        }
        
    }
}


struct BeerViewModel {
    
    let beer: Beer
    
    var bid: Int {
        beer.bid
    }
    
    var beerName: String {
        beer.beerName
    }
    
    var beerLabel: String {
        beer.beerLabel
    }
    
    var beerAbv: Double {
        beer.beerAbv
    }
    
    var beerIbu: Int {
        beer.beerIbu
    }
    
    var beerDescription: String {
        beer.beerDescription
    }
    
}

I had a similar issue. Using the .task modifier to run some asynchronous code would work properly and the UI update in iOS 16 (beta) but would not update the UI in iOS 15. The fix was to use the .onAppear modifier instead. This updated the UI in both iOS 16 and iOS 15 correctly.

Were you able to solve your issue, am having a similar issue. The UI is only being updated when the function that changes my @State variable is synchronous, and the UI will not update when the @State variable is modified by an asynchronous function call.

Why won't SwiftUI view update based on async task results (new to SwiftUI)
 
 
Q