Pak Ho Cheung
Pak Ho Cheung

Reputation: 1416

fatal error: Array index out of range. Swift when refresh

Tried so many times to find out what causes the fatal error. But, still can't figure it out. The first table (result table) causes this error when I try to refresh the table with pull. The second table (favoriteProductTableView) works perfect, so I didn't put any code about the second one. Wondering why. Thank you for your help.

    var followArray = [String]()
    var resultsNameArray = [String]()
    var resultsImageFiles = [PFFile?]()
    var resultsDetailsArray = [String]()
    var resultsDetailsImageFiles = [PFFile?]()
    var resultsObjectID = [String]()
    var resultsTitle = [String]()
    var personPriceArray = [String]()
    var personQuantityArray = [String]()
    var personOrderTypeArray = [String]()

    var refresher:UIRefreshControl!

    override func viewDidLoad() {
        super.viewDidLoad()
        favoriteProductTableView.hidden = true
        refresher = UIRefreshControl()
        refresher.tintColor = UIColor.blackColor()
        refresher.addTarget(self, action: "refresh", forControlEvents: UIControlEvents.ValueChanged)
        self.resultsTable.addSubview(refresher)
    }

    override func viewDidAppear(animated: Bool) {
        refreshResults()
    }

    func refresh(){
        refreshResults()
    }

    func refreshResults(){
        switch(segmentedControl.selectedSegmentIndex){
        case 0:
            followArray.removeAll(keepCapacity: false)
            resultsNameArray.removeAll(keepCapacity: false)
            resultsImageFiles.removeAll(keepCapacity: false)
            resultsDetailsArray.removeAll(keepCapacity: false)
            resultsDetailsImageFiles.removeAll(keepCapacity: false)
            resultsObjectID.removeAll(keepCapacity: false)
            resultsTitle.removeAll(keepCapacity: false)
            personPriceArray.removeAll(keepCapacity: false)
            personQuantityArray.removeAll(keepCapacity: false)
            personOrderTypeArray.removeAll(keepCapacity: false)

            let followQuery = PFQuery(className: "follow")
            followQuery.whereKey("user", equalTo: (PFUser.currentUser()!.username)!)
            followQuery.whereKey("userToFollow", notEqualTo: (PFUser.currentUser()!.username)!)

            followQuery.findObjectsInBackgroundWithBlock { (objects:[PFObject]?, error: NSError?) -> Void in
                if error != nil {
                }
                for object in objects! {
                    self.followArray.append(object.objectForKey("userToFollow") as! String)
                }
                let query = PFQuery(className: "products")
                query.whereKey("userName", containedIn: self.followArray)

                query.findObjectsInBackgroundWithBlock { (catchobjects:[PFObject]?, error:NSError?) -> Void in
                    if error != nil {
                    }
                    for catchobject in catchobjects! {
                        if catchobject.objectForKey("selling_price") != nil {
                            self.personPriceArray.append(catchobject.objectForKey("selling_price") as! String)
                            self.personOrderTypeArray.append("Selling")
                        } else {
                            self.personPriceArray.append(catchobject.objectForKey("buying_price") as! String)
                            self.personOrderTypeArray.append("Buying")
                        }
                        self.personQuantityArray.append(catchobject.objectForKey("quantity") as! String)
                        self.resultsNameArray.append(catchobject.objectForKey("unique_username") as! String)
                        self.resultsImageFiles.append(catchobject.objectForKey("profile_picture") as? PFFile)
                        self.resultsDetailsArray.append(catchobject.objectForKey("details") as! String)
                        self.resultsDetailsImageFiles.append(catchobject.objectForKey("detailsImage") as? PFFile)
                        self.resultsTitle.append(catchobject.objectForKey("title") as! String)
                        self.resultsObjectID.append(catchobject.objectId!)
                    }
                    dispatch_async(dispatch_get_main_queue()) {
                        self.resultsTable.reloadData()
                    }
                    self.loadEmptyLabel(self.resultsTable)
                }
                self.refresher.endRefreshing()
            }
            break
        case 1:
            ...
            break
        default:
            break
        }
    }

    func loadEmptyLabel(tableView: UITableView) {
        let emptyLabel = UILabel(frame: CGRectMake(0, 0, UIScreen.mainScreen().bounds.width, UIScreen.mainScreen().bounds.height))
        emptyLabel.textAlignment = NSTextAlignment.Center
        emptyLabel.textColor = UIColor.blackColor()
        emptyLabel.text = "No matched result found."
        tableView.backgroundView = emptyLabel
        tableView.separatorStyle = UITableViewCellSeparatorStyle.None
        var resultCount = Int()
        if tableView == resultsTable {
            resultCount = resultsNameArray.count
        } else {
            resultCount = resultsTitleArray.count
        }
        if resultCount == 0 {
            tableView.reloadData()
            emptyLabel.hidden = false
        } else {
            emptyLabel.hidden = true
        }
    }

    func tableView(tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
        var numRow: Int = 0
        switch(segmentedControl.selectedSegmentIndex){
        case 0:
            numRow = resultsNameArray.count
            break
        case 1:
            numRow = resultsTitleArray.count
            break
        default:
            break
        }
        return numRow
    }

    func tableView(tableView: UITableView, cellForRowAtIndexPath indexPath: NSIndexPath) -> UITableViewCell {
        if tableView == resultsTable {
            let cell:favoritedTableViewCell = resultsTable.dequeueReusableCellWithIdentifier("Cell") as! favoritedTableViewCell
            cell.profileLbl.text = self.resultsNameArray[indexPath.row]
            cell.messageTxt.text = self.resultsDetailsArray[indexPath.row]
            cell.priceLabel.text = "\(self.personOrderTypeArray[indexPath.row]) \(self.personQuantityArray[indexPath.row]) for $\(self.personPriceArray[indexPath.row])"
            cell.titleLabel.text = self.resultsTitle[indexPath.row]
            if resultsImageFiles[indexPath.row] != nil {
                resultsImageFiles[indexPath.row]!.getDataInBackgroundWithBlock { (imageData:NSData?, error:NSError?) -> Void in
                    if error == nil{
                        let image = UIImage(data: imageData!)
                        cell.imgView.image = image
                    }
                }
            } else {
                cell.imgView.image = UIImage(named: "Profile Picture")
            }
            if resultsDetailsImageFiles[indexPath.row] != nil{
                resultsDetailsImageFiles[indexPath.row]?.getDataInBackgroundWithBlock({ (imageData:NSData?, error:NSError?) -> Void in
                    if error == nil{
                        let image = UIImage(data: imageData!)
                        cell.detailsImg.image = image
                    }
                })
            } else {
                cell.detailsImg.image = UIImage(named: "Profile Picture")
            }
            return cell
        } else {
        ....
        }
    }

Upvotes: 0

Views: 674

Answers (1)

Michael
Michael

Reputation: 9044

Your numberOfRowsInSection function returns one of two array lengths based on segmentedControl.selectedSegmentIndex, whereas cellForRowAtIndexPath indexes the arrays based on the tableView being displayed. This doesn't look right, especially given your referencing `` which doesn't appear to be populated anywhere - should it just be resultsTitle?.

Also, you're calling self.resultsTable.reloadData() from a background thread. This is bad - it must be called from the main thread using:

dispatch_async(dispatch_get_main_queue()) {
    self.resultsTable.reloadData()
}

Nevertheless, it's not clear why you've got this inside the loop either.

Upvotes: 1

Related Questions