Welcome to OStack Knowledge Sharing Community for programmer and developer-Open, Learning and Share
Welcome To Ask or Share your Answers For Others

Categories

0 votes
219 views
in Technique[技术] by (71.8m points)

swift - How to retrieve data from Firestore as soon as SwiftUI view appears?

I have this class CurrentUser that manages the currently logged in user and pulls the data for that user from Firebase.

One of CurrentUser's attributes is userEventIDs. I also have a collection of Events documents. Each user has their own array of event IDs that correspond to the events within the Events collection in my Firestore database.

On the MyAccount view struct I have an onAppear method that queries the Events collection based on the currentUser's array of eventIds, returns those Events, and then sorts them to be either before or after today based on the date of the event.

Currently the eventIds load in the first time this view is opened, but the query from the events comes back blank twice and only after the view is switched to another one and back to the MyAccount view will the page populate with these events.

Is there something I can do to make the events load on the first time the view is opened?

CurrentUser

class CurrentUser: ObservableObject {
  let user = Auth.auth().currentUser
  
  @Published var currentUserInformation = User(id: "", name: "", email: "'", accountType: "", profPicURL: "", coverPhotoURL: "", numberFollowers: nil, description: nil, location: nil, websiteLink: nil, orgID: nil, userEventIDs: [String](), userEvents: [Event]())
  
  init() {
    getUserInformation()
  }
  
  func getUserInformation() {
    let UID = user!.uid
    let database = Firestore.firestore()
    database.collection("Organizers").whereField("Organizer ID", isEqualTo: UID).getDocuments() { (querySnapshot, err) in
      
      if err != nil {
        print("Error getting documents: (err!)")
      }
      
      for document in querySnapshot!.documents {
        self.currentUserInformation.id = document.documentID
        self.currentUserInformation.name = document.get("Organization Name") as! String
        self.currentUserInformation.email = document.get("Email") as! String
        self.currentUserInformation.accountType = document.get("Account Type") as! String
        self.currentUserInformation.profPicURL = document.get("Profile Pic URL") as! String
        self.currentUserInformation.coverPhotoURL = document.get("Cover Pic URL") as! String
        self.currentUserInformation.numberFollowers = (document.get("Number of Followers") as! Int)
        self.currentUserInformation.description = (document.get("Organization Description") as! String)
        self.currentUserInformation.websiteLink = (document.get("Organization Website Link") as! String)
        self.currentUserInformation.location = (document.get("Organization Location") as! String)
        self.currentUserInformation.orgID = (document.get("Organizer ID") as! String)
        self.currentUserInformation.userEventIDs = (document.get("Events") as! [String])
        self.currentUserInformation.accountType = "Organizer"
      }
    }
    
    if self.currentUserInformation.id == "" {
      database.collection("Activists").whereField("UID", isEqualTo: UID).getDocuments() { (querySnapshot, err) in
        
        if err != nil {
          print("Error getting documents: (err!)")
        }
        
        for document in querySnapshot!.documents {
          
          self.currentUserInformation.id = document.documentID
          let firstName = document.get("First Name") as! String
          let lastName = document.get("Last Name") as! String
          self.currentUserInformation.name = "(firstName) (lastName)"
          self.currentUserInformation.email = document.get("Email") as! String
          self.currentUserInformation.accountType = "Activist"
          self.currentUserInformation.profPicURL = document.get("Profile Pic") as! String
          self.currentUserInformation.userEventIDs = (document.get("Events") as! [String])
          
        }
      }
    }
  }
  
  func getUserEvents() {
    let database = Firestore.firestore()
    let eventRef = database.collection("Events")
    for eventID in self.currentUserInformation.userEventIDs {
      for event in self.currentUserInformation.userEvents {
        if event.id == eventID {
          break
        }
      }
      eventRef.document(eventID).getDocument() { (document, error) in
        if let document = document {
          let id = document.documentID
          let eventTitle = document.get("Name") as! String
          let organizer = document.get("Organizer") as! String
          let organizerID = document.get("Organizer ID") as! String
          let eventDescription = document.get("Description") as! String
          let date = document.get("Date") as! String
          let time = document.get("Time") as! String
          let location = document.get("Location") as! String
          let numAttending = document.get("Number Attending") as! Int
          let eventPhotoURL = document.get("Event Photo URL") as! String
          self.currentUserInformation.userEvents.append(Event(id: id, eventTitle: eventTitle, eventOrganizer: organizer, eventOrganizerID: organizerID, eventDescription: eventDescription, date: date, time: time, location: location, numAttending: numAttending, eventPhotoURL: eventPhotoURL))
        } else {
          print("Document does not exist")
        }
      }
    }
  }
}

View

.onAppear() {
    if currentActivist.currentUserInformation.userEvents.count != currentActivist.currentUserInformation.userEventIDs.count {
    currentActivist.getUserEvents()
      print("Getting user events")
    }
    pastEvents = MyAccountActivistView.getSortedEvent(actEvents: currentActivist.currentUserInformation.userEvents)["Past"]!
    futureEvents = MyAccountActivistView.getSortedEvent(actEvents: currentActivist.currentUserInformation.userEvents)["Upcoming"]!
  }
question from:https://stackoverflow.com/questions/65912551/how-to-retrieve-data-from-firestore-as-soon-as-swiftui-view-appears

与恶龙缠斗过久,自身亦成为恶龙;凝视深渊过久,深渊将回以凝视…
Welcome To Ask or Share your Answers For Others

1 Answer

0 votes
by (71.8m points)

A couple of quick notes:

  1. Most Firebase calls are asynchronous (check out this article to understand why), so your call to Auth.auth().currentUser is most likely going to return nil. Instead, you should register an AuthenticationStateListener. See this sample code to see how it's done.
  2. Instead of instantiating an empty User instance, make currentUserInformation optional
  3. Mapping data is much easier using Firestore's support for Codable. I've written extensively about this, but the gist of it is, you'll be able to map documents with a single line of code (instead of having to manually map every single field). The Firestore documentation actually has a nice code snippet that you can adopt:
let docRef = db.collection("cities").document("BJ")

docRef.getDocument { (document, error) in
    // Construct a Result type to encapsulate deserialization errors or
    // successful deserialization. Note that if there is no error thrown
    // the value may still be `nil`, indicating a successful deserialization
    // of a value that does not exist.
    //
    // There are thus three cases to handle, which Swift lets us describe
    // nicely with built-in Result types:
    //
    //      Result
    //        /
    //   Error  Optional<City>
    //               /
    //            Nil  City
    let result = Result {
      try document?.data(as: City.self)
    }
    switch result {
    case .success(let city):
        if let city = city {
            // A `City` value was successfully initialized from the DocumentSnapshot.
            print("City: (city)")
        } else {
            // A nil value was successfully initialized from the DocumentSnapshot,
            // or the DocumentSnapshot was nil.
            print("Document does not exist")
        }
    case .failure(let error):
        // A `City` value could not be initialized from the DocumentSnapshot.
        print("Error decoding city: (error)")
    }
}
  1. Avoid force unwrapping (using the ! operator), use optional unwrapping (using the ? operator), and the nil-coalescing operator (??) instead

与恶龙缠斗过久,自身亦成为恶龙;凝视深渊过久,深渊将回以凝视…
Welcome to OStack Knowledge Sharing Community for programmer and developer-Open, Learning and Share
Click Here to Ask a Question

...