SwiftUI: Generic parameter 'Subject' could not be inferred

Teetz picture Teetz · Aug 9, 2019 · Viewed 9.1k times · Source

I built a LoadingView with SwiftUI for showing some loading stuff in my app while I'm fetching remote data from an API. I am on Xcode Version 11.0 beta 5.

This is the LoadingView:

struct LoadingView<Content>: View where Content: View {

    @Binding var isShowing: Bool
    var content: () -> Content

    var body: some View {

        GeometryReader { geometry in

            ZStack(alignment: .center) {

                self.content()
                    .disabled(self.isShowing)
                    .blur(radius: self.isShowing ? 3 : 0)

                VStack {
                    Text("Loading...")
                    ActivityIndicator(isAnimating: .constant(true), style: .large)
                }
                .frame(width: geometry.size.width / 2,
                       height: geometry.size.height / 5)
                    .background(Color.white)
                    .foregroundColor(Color.primary)
                    .cornerRadius(5)
                    .opacity(self.isShowing ? 1 : 0)
            }
        }
    }
}

This is my DataStore. It is declared as ObservableObject and has more than one @Published property. Also it does some remote fetching from an API:

class CharacterStore: ObservableObject {

    @Published private(set) var isLoading = false


    // Fetches some stuff from a remote api
    func fetch() {

        self.isLoading = true

        myService.getCharacters { (result) in
            DispatchQueue.main.async {
                self.isLoading = false
            }
        }
    }
}

And finally this is the View I want to show my LoadingView with the content of ContentView in it. Of course I am setting the @EnvironmentObject before showing this view.

struct ContentView: View {

    @EnvironmentObject var charStore: CharacterStore

    var body: some View {

        LoadingView(isShowing: self.$charStore.isLoading) { // Here I get the error

            // Show some Content here
            Text("")
        }
    }
}

The problem is that I want to bind self.$charStore.isLoading to LoadingView. In this line i get the following error:

Generic parameter 'Subject' could not be inferred

I tried in several ways but none of these things work. Btw: If I use a @State property in ContentView it just works fine like this:

struct ContentView: View {

    @EnvironmentObject var charStore: CharacterStore

    @State var loads: Bool = false

    var body: some View {

        LoadingView(isShowing: self.$loads) { // Here I get no error

            // Show some Content here
            Text("")
        }
    }
}

Am I missing a thing? If you need further informations let me know i can provide more content if needed.

Thanks for the help!

Answer

kontiki picture kontiki · Aug 9, 2019

Since your LoadingView is not going to modify .isLoading, you do not need to pass it as a binding:

LoadingView(isShowing: self.$charStore.isLoading)

Instead, remove the @Binding in LoadingView:

struct LoadingView<Content>: View where Content: View {

    var isShowing: Bool
    ...

and create it like this (remove the dollar sign):

LoadingView(isShowing: self.charStore.isLoading) { ... }

On the contrary, if you insist on passing a binding, then you need to remove the private(set) from:

@Published private(set) var isLoading = false