ewang
ewang

Reputation: 506

Create optional @StateObject

I'm trying to create an @EnvironmentObject called "userData" to share data about the user between views. I am trying to create an optional @StateObject "userData" and then initialize the @StateObject "userData" once the user has logged in since I need to know the user's userID to initialize the @StateObject "userData".

This is what my code looks like:

class User: ObservableObject {
  var collection: CollectionReference

  init(userID: String) { 
    collection = Firestore.firestore().collection(userID)
  }
  ...
}

struct ContentView: View {
  @StateObject var userData: User? = nil

  ...
  
  NavigationLink(destination: HomePage(), isActive: $action) {
    EmptyView().environmentObject(userData)
  }

  Button(action: {
    Auth.auth().signIn(withEmail: self.email ?? "", password: self.password ?? "") { authResult, error in
      if let user = authResult?.user {
        userData = User(userID: user.uid)
        self.action = true 
      } else {
        print("failed :(: \(error)")
      }
    }
  })
  ...
}

struct HomePage: View {
  @EnvironmentObject var userData: User


  ...
}

However, SwiftUI doesn't seem to be recognizing userData as optional because I keep getting the error:

Generic struct 'StateObject' requires that 'User?' conform to 'ObservableObject'

Is there a way to declare optional @StateObject variables? Or else is there another way to initialize the @StateObject later on in a function?

Upvotes: 5

Views: 3922

Answers (1)

jnpdx
jnpdx

Reputation: 52565

As suggested in the comments, you could make collection optional, since you can't have an optional StateObject:

class User: ObservableObject {
  var collection: CollectionReference?

  func loadCollection(userID: String) {
    collection = Firestore.firestore().collection(userID)
  }
}

//...

@StateObject var userData = User()

//...

Button(action: {
    Auth.auth().signIn(withEmail: self.email ?? "", password: self.password ?? "") { authResult, error in
      if let user = authResult?.user {
        userData.loadCollection(userID: user.uid)
        self.action = true 
      } else {
        print("failed :(: \(error)")
      }
    }
  })

Upvotes: 1

Related Questions