Share Data Binding Between Class and Struct View

Viewed 231

For example, when I get data from API success or unsuccess I would like to show Alert but Alert there need isPresented type is Binding that's why I want to use concept Share Data as Binding between class and View is possible or have another way to do please help thanks advance.

1 Answers

@Published properties work well for sharing data between ObservableObjects and Views.

For example:

class ViewModel : ObservableObject {
    struct APIError : Identifiable {
        var id = UUID()
        var message : String
    }
    
    @Published var error : APIError?
    
    func apiCall() {
        DispatchQueue.main.asyncAfter(deadline: .now() + 1) {
            self.error = APIError(message: "Error message")
        }
    }
}

struct ContentView : View {
    @StateObject var viewModel = ViewModel()
    
    var body: some View {
        VStack {
            Text("Hello, world!")
                .alert(item: $viewModel.error) { item in
                    Alert(title: Text(item.message))
                }
        }
        .onAppear {
            viewModel.apiCall()
        }
    }
}

You could also do this with a custom Binding, but it's a little messier. The above example would definitely be my go-to.

class ViewModel : ObservableObject {
    @Published var errorMessage : String?
    
    var alertBinding : Binding<Bool> {
        .init {
            self.errorMessage != nil
        } set: { newValue in
            if !newValue { self.errorMessage = nil }
        }

    }
    
    func apiCall() {
        DispatchQueue.main.asyncAfter(deadline: .now() + 1) {
            self.errorMessage = "Error!"
        }
    }
}

struct ContentView : View {
    @StateObject var viewModel = ViewModel()
    
    var body: some View {
        VStack {
            Text("Hello, world!")
                .alert(isPresented: viewModel.alertBinding) {
                    Alert(title: Text(viewModel.errorMessage ?? "(unknown)"))
                }
        }
        .onAppear {
            viewModel.apiCall()
        }
    }
}
Related