简体   繁体   中英

Why do I always get an Index out of range error, when trying to reload data?

I'm trying to retrieve data from my Firebase database, about the number of "effects" contained as a number in my posts collection. I want this data to update every time the effectIsTapped function is called. Then, I want the array to update. Currently, I am removing all elements from the EffectsLabelArray , before adding data. But, without fail, this produces a "Fatal Error: Index out of range", at the line:

 let effects = self.effectsLabelArray[indexPath.row]

Below I detail my code:

var titleArray: [String] = []
var usernameArray: [String] = []
var contentArray: [String] = []
var postedTimeArray: [Any] = []
var effectsLabelArray: [Int] = []
var profileImageArray: [String] = []
var postIDArray: [Int] = []
var followingList: [String] = []
var documents: [DocumentSnapshot] = []

let db = Firestore.firestore()
let currentUserID = Auth.auth().currentUser?.uid

    // Find the UserIDs of people following
// Where Field for those UserIDs in "Posts"


override func viewDidLoad() {
    super.viewDidLoad()
   // getFollowingPosts()
    configureTableView()
    getFollowingPosts()
    
    
    
    
}
            func getFollowingPosts() {
            db.collection("iAmFollowing").document(currentUserID!).getDocument { (document, error) in
                if error != nil {
                    print("ERROR")
                } else {
                    if let document = document, document.exists {
                        let followedUID = document.get("uid") as? String
                        
                        
                        self.db.collection("posts").whereField("uid", isEqualTo: followedUID!).getDocuments { (documents, error) in
                            for documents in documents!.documents {
                                let title = documents.get("Title") as! String
                                let content = documents.get("Content") as! String
                                let username = documents.get("username") as! String
                                let postID = documents.get("postID")
                                let counter = documents.get("counter")
                                self.titleArray.append(title)
                                self.contentArray.append(content)
                                self.usernameArray.append(username)
                                self.postIDArray.append(postID as! Int)
                                self.effectsLabelArray.append(counter as! Int)
                                print(self.titleArray)
                                self.tableView.reloadData()
                                }
                            }
                        }
                    }
                    
                    }
}
    
    







func configureTableView() {
    tableView.delegate = self
    tableView.dataSource = self

    // remove separators for empty cells
    tableView.tableFooterView = UIView()
    // remove separators from cells
    tableView.separatorStyle = .none
}

func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
    titleArray.count
}

func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
    let cell = tableView.dequeueReusableCell(withIdentifier: "PostCell", for: indexPath) as! PostCell
    db.collection("iAmFollowing").document(currentUserID!).getDocument { (document, error) in
        if let document = document, document.exists {
            let followedUID = document.get("uid") as! String
            self.db.collection("posts").whereField("uid", isEqualTo: followedUID).getDocuments { (documents, error) in
        for documents in documents!.documents {
            let counter = documents.get("counter") as! Int
            self.effectsLabelArray.append(counter)
            
            let postID = self.postIDArray[indexPath.row]
            let title = self.titleArray[indexPath.row]
            let content = self.contentArray[indexPath.row]
            let username = self.usernameArray[indexPath.row]
            let effects = self.effectsLabelArray[indexPath.row]
            
            cell.titleLabel.text = title
            cell.contentLabel.text = content
            cell.usernameLabel.text = username
            cell.postIDLabel.text = String(postID)
            cell.effectsLabel.text = String(effects)
        }
    }
    //Get effects
    //Append Effects
    //Set title to indexPath.row
    //Set them to cell label
    
        }
    }
    return cell
}

@IBAction func effectsButtonIsTapped(_ sender: Any) {
    DispatchQueue.main.asyncAfter(deadline: .now() + 0.05) {
        self.effectsLabelArray.removeAll()
        self.tableView.reloadData()
    }
}

    // Do any additional setup after loading the view.
@IBAction func removeEffectIsTapped(_ sender: Any) {
    DispatchQueue.main.asyncAfter(deadline: .now() + 0.05) {
        self.effectsLabelArray.removeAll()
        self.tableView.reloadData()
    }
}



@IBAction func logoutIsTapped(_ sender: Any) {
    try! Auth.auth().signOut()
    let loginDialogueViewController = storyboard?.instantiateViewController(withIdentifier: "LoginDialogueViewController")
    let navigationController = UINavigationController(rootViewController: loginDialogueViewController!)
    let share = UIApplication.shared.delegate as? AppDelegate
    share?.window?.rootViewController = navigationController
    share?.window?.makeKeyAndVisible()
    navigationController.modalPresentationStyle = .fullScreen
    present(navigationController, animated: false)
}
/*
// MARK: - Navigation

// In a storyboard-based application, you will often want to do a little preparation before navigation
override func prepare(for segue: UIStoryboardSegue, sender: Any?) {
    
}
*/

}

If anyone can answer this for me, I would be greatly appreciative.

First, try not to call reloadData() on a loop. That might cause unwanted side effect. Try to add everything up to the array while querying the db, after all of the data is in the array, only then you call the reloadData() . As it will invalidate everything in the UITableView and re-load all the necessary data and cells.

The same goes while you are displaying the cell tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell . Only set the property of the cell after everything fetched from the db, do not access the UI level repeatedly. That can cause hitch and your app un-responsive for a period of time. Will go exponentially as the data grows.

Then, effectsLabelArray got edited in other places as well, then you can never be sure the count nor the size of that array. Instead of getting via self.effectsLabelArray[indexPath.row] try using self.effectsLabelArray[safe: index.row] . Then you can add extra handling when the expected value are not there.

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM