0

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"]!
  }
4

1 回答 1

0

几个快速说明:

  1. 大多数 Firebase 调用都是异步的(查看这篇文章以了解原因),因此您的调用Auth.auth().currentUser很可能会返回nil. 相反,您应该注册一个AuthenticationStateListener. 请参阅此示例代码以了解它是如何完成的。
  2. 而不是实例化一个空User实例,使currentUserInformation可选
  3. 使用 Firestore 对 Codable 的支持更容易映射数据。我已经写了很多关于这个的文章,但它的要点是,您将能够使用一行代码映射文档(而不必手动映射每个字段)。Firestore 文档实际上有一个不错的代码片段,您可以采用:
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. 避免强制展开(使用 ! 运算符),使用可选展开(使用 ? 运算符)和nil-coalescing 运算符(??)
于 2021-01-27T09:54:24.340 回答