0

My apologies if this is a very basic question, I am new to both Swift and Firebase. I have a to-do list app which uses Firestore as the backend. In the future, I plan to add multi-user support for shared to-do lists.

The problem I'm encountering is that when I use the loadItems() and the loadSections() functions to refresh my tableView, the array gets duplicated. This results in a strange-looking effect.

Link to screen record: https://www.dropbox.com/s/cd9084skr2x26li/Screen%20Recording%202020-07-21%20at%2017.51.07.mov?dl=0

My loadItems() and loadSections()

//MARK: - Load sections
func loadSections(listID: String) {
    // print("Loading sections...")
    let listRef = db.collection(K.FStore.lists).document(listID)
    
    listRef.getDocument { (document, error) in
        if let document = document, document.exists {
            let dataDescription = document.data().map(String.init(describing:)) ?? "nil"
            let sectionNames = document.data()![K.List.sections] as? [String]
            
            self.sections.removeAll()
            if let sectionNames = sectionNames {
                for (index, item) in sectionNames.enumerated() {
                    let newSection = Section(name: item, isExpanded: true, items: [])
                    self.sections.append(newSection)
                    self.loadItems(listID: listID, section: index)
                }
            }
            
            
            self.tableView.reloadData()
            
        } else {
            print("Document does not exist")
        }
    }
}



//MARK: - Load items

func loadItems(listID: String, section: Int) {
    
    var newItems = [Task]()
    // self.sections[section].items.removeAll()
    let itemRef = db.collection(K.FStore.lists).document(listID).collection(K.FStore.sections).document("\(section)").collection(K.FStore.items)
    
    itemRef.addSnapshotListener { querySnapshot, error in
        guard let documents = querySnapshot?.documents else {
               print("Error fetching documents: \(error!)")
               return
           }
        for document in documents {
            print("Name: \(document.data()[K.Item.name])")
            let name = document.data()[K.Item.name] as! String
            let isChecked = document.data()[K.Item.isChecked] as! Bool
            let documentID = document.documentID as! String

            let newTask = Task(name: name, isChecked: isChecked, itemID: documentID)
            newItems.append(newTask)
        }
        self.sections[section].items.removeAll()
        if section == 2 {
            print(newItems.count)
        }
        self.sections[section].items = newItems
        self.tableView.reloadData()
    } }

My viewDidLoad() (where I call the function)

var sections: [Section] = []

// Database references
let db = Firestore.firestore()
var items: [Task]?

override func viewDidLoad() {
    super.viewDidLoad()
    
    // Storing user variables locally
    let user = Auth.auth().currentUser
    if let user = user {
        currentUserID = user.uid
        userRef = db.collection(K.FStore.users).document(currentUserID!)
        userRef!.getDocument { (snapshot, error) in
            if let data = snapshot?.data() {
                self.userFirstName = (data[K.User.firstName] as! String)
                self.userEmail = (data[K.User.email] as! String)
                self.currentLists = (data[K.User.lists] as! [String])
                self.currentListID = self.currentLists![0]
                self.listsRef = self.db.collection(K.FStore.lists).document(self.currentListID!)
                
                // Load the section names
                self.loadSections(listID: self.currentListID!)
                
            } else {
                print("Could not find document")
            }
        }
    } }

In my addTask() and checkTask() I call this function

func refreshTable() {
    
    loadSections(listID: currentListID!)
    tableView.reloadData()
}

How will I be able to fix this issue?

Many thanks, Matt

M. Tol
  • 55
  • 10
  • Every time data is changed in the database, your listener is called again will all data. So you'll either need to only show the changes, or (more commonly) clear the array when you get new data. See https://stackoverflow.com/questions/54740003/duplicate-collectionview-cells-after-reloaddata-with-firebase-query (and many others in https://stackoverflow.com/search?q=%5Bgoogle-cloud-firestore%5D%5Bswift%5D+duplicate) – Frank van Puffelen Jul 21 '20 at 16:01
  • Note that since you're using `addSnapshotListener` your code gets executed right away with the existing documents, but then keeps monitoring for changes. If you don't want it to keep monitoring, use `getDocuments` instead as shown here: https://firebase.google.com/docs/firestore/query-data/get-data#get_multiple_documents_from_a_collection. – Frank van Puffelen Jul 21 '20 at 16:02
  • Thank you so much Frank! It's working perfectly now. – M. Tol Jul 21 '20 at 16:09

0 Answers0