Search code examples
arraysswiftuitableviewgoogle-cloud-firestoreuisegmentedcontrol

cell text is not changing when segment value changed


So my goal is to have the tableview cell text change when the segment value is changed. The first segment I have is for all events and the second segment is for purchased events. When the view loads it successfully displays all the events available, but when I change the segment value to purchased, the cell text stays the same and I want to know how I can fix this.

I created a function to grab the purchased event names from the Firestore database.

func getPurchasedEventName() -> String{
    getStudentID { (studid) in
        if let id = studid {
            self.docListener = self.db.collection("student_users/\(self.user?.uid)/events_bought").whereField("school_id", isEqualTo: id).order(by: "time_purchased", descending: true).addSnapshotListener(includeMetadataChanges: true) { (querySnapshot, error) in
                if error != nil {
                    print("Error fetching docs/ User deletion.")
                } else {
                    self.gotherePurchasedEvents = querySnapshot!.documents.map { document in
                        return PurchasedEventName(purchasedEventName: (document.get("event_name") as! String))
                    }
                    self.tableView.reloadData()
                }
            }
        }
    }

    return "\(gotherePurchasedEvents)"
}

This function is identical to the function I used to get all the event names, so I thought it would get the job done. Here is that identical function:

func getSchoolID() -> String {
    //Putting the function in a completion handler
     getStudentGrade { (studentGrade) in
        if let gradeForStudent = studentGrade {
            self.getStudentID { (studentID) in
                if let idForStudent = studentID {
                    self.docListener = self.db.collectionGroup("events").order(by: "time_created", descending: true).whereField("school_id", isEqualTo: idForStudent).whereField("for_grades", isEqualTo: gradeForStudent).addSnapshotListener(includeMetadataChanges: true) { (querySnapshot, error) in
                        if error != nil {
                            print("Error/ User Deletion")
                        } else {
                            self.gothereEvents = querySnapshot!.documents.map { document in
                                return EventName(eventName: (document.get("event_name") as? String) ?? "")
                            }
                            self.tableView.reloadData()
                        }
                    }
                }
            }
        }
    }
  

This grabs all the events.

Now I was getting a couple of index out of range errors as well while playing with the code, so I was checking tableView methods but couldn't see the issue, I'll attach those as well.

  func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
    let cell = tableView.dequeueReusableCell(withIdentifier: Constants.CellDetails.studentDashCell, for: indexPath)
    if eventListSelector.selectedSegmentIndex == 0 {
        cell.textLabel?.text = gothereEvents[indexPath.row].eventName
    } else if eventListSelector.selectedSegmentIndex == 1 {
        cell.textLabel?.text = gotherePurchasedEvents[indexPath.row].purchasedEventName
    }
    
    return cell
}

The cellForRowAt() method.

func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
    
    if eventListSelector.selectedSegmentIndex == 0 {
        tableView.separatorColor = #colorLiteral(red: 0.3084011078, green: 0.5618229508, blue: 0, alpha: 1)
        tableView.separatorStyle = .singleLine
        return gothereEvents.count
    } else if eventListSelector.selectedSegmentIndex == 1 {
        tableView.separatorColor = #colorLiteral(red: 0.3084011078, green: 0.5618229508, blue: 0, alpha: 1)
        tableView.separatorStyle = .singleLine
        return gotherePurchasedEvents.count
    } else {
        tableView.separatorStyle = .none
        return 0
    }
    
    
}

The numberOfRowsInSection() method.

Now the thing with the events_bought collection, is that it can be empty and only have a test document, so i added indexes to filter out the query if you look in the getThePurchasedEventName() method. I tested it out by purchasing two events and making a function to check if they were actually in there.

  func checkIfEventsHaveActuallyBeenBought() {
    getStudentID { (studid) in
        if let id = studid {
            self.db.collection("student_users/\(self.user?.uid)/events_bought").whereField("school_id", isEqualTo: id).order(by: "time_purchased", descending: true).addSnapshotListener { (querySnapshot, error) in
                if error != nil {
                    print("Error loading docs")
                } else {
                    for document in querySnapshot!.documents {
                        print("\(document.data())")
                    }
                }
            }

        }
    }
}

This worked and printed two documents, but I can't figure out why when I switch the segmented control value, the cell text doesn't change to show the purchased events. If you need more clarification feel free to ask questions.


Solution

  • The relevant UISegementedControl code is missing, so I can't be certain, but it appears that you are expecting the tableview to automatically respond to changes in the segmented control? This isn't how it works. While your tableview methods will work to produce the correct cells for the current status of the segmented control, you are not telling them to do so when segmented control changes.

    You need to use the control's target-action methods and to register for and respond to the value changed event.

    When you set up the control you need to register for the event, and then implement the selector to respond to that event

    
    //wherever you set up the seg control
    let segmentedControl = UISegmentedControl(items:["All","Purchased"])
    segmentedControl.addTarget(self, action: #selector(segDidChange), for: .valueChanged)
    
    
    //then implement the selector method
    @objc func segDidChange(control: UISegmentedControl) {
          tableView.reloadData()
    }
    

    This is a crude implmentation that just forces a tableview reload to refresh all the cells. You may be able to do something more clever, maybe with the new tableview diffing methods.