Abhi Ram
Abhi Ram

Reputation: 53

SwiftUI @EnvironmentObject no ObservableObject of type error

I am getting the error

Fatal error: No ObservableObject of type LoginResponse found. A View.environmentObject(_:) for LoginResponse may be missing as an ancestor of this view.

I have passed the environment object to all the subviews of LoginView(), but the error still persists

struct LoginView: View {
    
    @State var loginCredentials = Credentials()
    var loginResponse = LoginResponse()
    var dataCall = DataCall()
    
    var body: some View {
        VStack{
            
            Button(action:{self.dataCall.AttemptLogin(loginCredentials: self.loginCredentials)}){
                
                Text("LOGIN")
                
            }
            
            Text("\(self.loginResponse.jwt)")
            
        }
        .environmentObject(self.loginResponse)
        .padding(.horizontal)
    }
}

Here is the rest of the code if needed

struct Credentials: Encodable {
    var login: String = ""
    var password: String = ""
}

class LoginResponse: Decodable, ObservableObject {
    
    enum CodingKeys: CodingKey {
        case success, userId, jwt
    }
    
    @Published var success: Bool = false
    @Published var userId: String = ""
    var error: String = ""
    @Published var jwt: String = ""
    init(){}
    required init(from decoder: Decoder) throws {
        let values = try decoder.container(keyedBy: CodingKeys.self)
        success = try values.decode(Bool.self, forKey: .success)
        userId = try values.decode(String.self, forKey: .userId)
        jwt = try values.decode(String.self, forKey: .jwt)
    }
}

struct DataCall {
    
    @EnvironmentObject var dataResponse : LoginResponse
    
    func AttemptLogin(loginCredentials: Credentials)  {
        
        let loginResponse = LoginResponse()
        dataResponse.success = loginResponse.success
        
        }
}

Upvotes: 0

Views: 231

Answers (1)

mginn
mginn

Reputation: 16104

Since DataCall is not a SwiftUI view, I don't believe you can use the .environmentObject modifier to pass data to it. Instead, just add a reference to a LoginResponse object in the DataCall struct, and pass it through the constructor like normal.

Example:

struct DataCall {
  weak var dataResponse : LoginResponse
  ...
}

let dataCall = DataCall(dataResponse: loginResponse)

However, I'm pretty confused about your view design. Any object that you declare normally in a View, without @State or @ObservedObject, will be recreated over and over again. Is that what you want?

Upvotes: 1

Related Questions