Search code examples
swiftuiobservedobject

Missing argument for parameter 'View Call' in call


I am struggle with understanding about why i have to give Popup view dependency named vm while calling this view since it is observable

 struct ContentView: View {
        @State private var showPopup1 = false
        var body: some View {
            VStack {
                Button(action: { withAnimation {  self.showPopup1.toggle()}}){
                    Text("showPopup1")  }
                Text("title")
               DetailView()  /// this line shows error
            }
           
        }
    }
    struct DetailView:View {
        @ObservedObject  var vm:ViewModel
        var body : some View {
            Text("value from VM")
            
        }
    }
    class ViewModel: ObservableObject {
        @Published var title:String = ""
        
    }

Solution

  • You have to set your vm property when you init your View. Which is the usual way.

    struct ContentView: View {
        @State private var showPopup1 = false
    
        var body: some View {
            VStack {
                Button(action: { withAnimation {  self.showPopup1.toggle()}}){
                    Text("showPopup1")  }
                Text("title")
    
                DetailView(vm: ViewModel()) // Initiate your ViewModel() and pass it as DetailView() parameter
            }
        }
    }
    
    struct DetailView:View {
    
        var vm: ViewModel
    
        var body : some View {
            Text("value from VM")
        }
    }
    
    class ViewModel: ObservableObject {
        @Published var title:String = ""
    }
    

    Or you could use @EnvironmentObject. You have to pass an .environmentObject(yourObject) to the view where you want to use yourObject, but again you'll have to initialize it before passing it.

    I'm not sure it's the good way to do it btw, as an environmentObject can be accessible to all childs view of the view you declared the .environmentObject on, and you usually need one ViewModel for only one View.

    struct ContentView: View {
        @State private var showPopup1 = false
        var body: some View {
            VStack {
                Button(action: { withAnimation {  self.showPopup1.toggle()}}){
                    Text("showPopup1")  }
                Text("title")
    
                DetailView().environmentObject(ViewModel()) // Pass your ViewModel() as an environmentObject
    
            }
        }
    }
    
    struct DetailView:View {
    
        @EnvironmentObject var vm: ViewModel // you can now use your vm, and access it the same say in all childs view of DetailView
    
        var body : some View {
            Text("value from VM")
        }
    }
    
    class ViewModel: ObservableObject {
        @Published var title:String = ""
    }