MattBlack MattBlack - 3 months ago 16
Swift Question

Swift Table index out of Range

I am new to swift and have set up a table which fills using data from an sql database.

The table loads fine but occasionally it gives the error: "Fatal Error: Index out of range".

It doesn't happen all the time just every now and again.

Also I have migrated from parse to using sql and http requests. Have I taken the correct approach to this when populating the data into the table?

Any help much appreciated!




@IBOutlet var tableView: UITableView!


var tableData = [String]()
var tableImages = [String]()

override func viewDidLoad() {
super.viewDidLoad()


}



override func viewDidAppear(animated: Bool) {

if Reachability.isConnectedToNetwork() == true {

self.tableView.hidden = true

self.tableData.removeAll(keepCapacity: true)
self.tableImages.removeAll(keepCapacity: true)

var nib = UINib(nibName: "vwTblCell3", bundle: nil)
tableView.registerNib(nib, forCellReuseIdentifier: "cell3")


let request = NSURLRequest(URL: NSURL(string: "********.php")!)


NSURLConnection.sendAsynchronousRequest(request, queue: NSOperationQueue(), completionHandler:{
(response: NSURLResponse?, data: NSData?, error: NSError?)-> Void in


let str2 = String(data: data!, encoding: NSUTF8StringEncoding)



let str3 = Int(str2!)!





let url = NSURL(string: "********")!

let task = NSURLSession.sharedSession().dataTaskWithURL(url) { (data, response, error) -> Void in

if let urlContent = data {



do {

let jsonResult = try NSJSONSerialization.JSONObjectWithData(urlContent, options: NSJSONReadingOptions.MutableContainers)


print(str3)

var i = 0

while i < str3 {

print(jsonResult[i]["title"]! as! String)
print(jsonResult[i]["image"]! as! String)

self.tableData.append(jsonResult[i]["title"]! as! String)
self.tableImages.append(jsonResult[i]["image"]! as! String)

i = i + 1

dispatch_async(dispatch_get_main_queue(), { () -> Void in
self.tableView.reloadData()
})

}

} catch {

print("JSON serialization failed")

}


}


}

task.resume()




});


print(tableData)


self.tableView.hidden = false


}

}


// 2
func tableView(tableView: UITableView, numberOfRowsInSection section: Int) -> Int {




return self.tableData.count
}


// 3
func tableView(tableView: UITableView, cellForRowAtIndexPath indexPath: NSIndexPath) -> UITableViewCell {
let cell: TblCell3 = self.tableView.dequeueReusableCellWithIdentifier("cell3") as! TblCell3
cell.lblAffiliate.text = tableData[indexPath.row]


let url3 = NSURL(string: "https://www.********.co.uk/\(tableImages[(indexPath as NSIndexPath).row]).png")
cell.affiliateImage.sd_setImageWithURL(url3)


return cell
}

// 4
func tableView(tableView: UITableView, didSelectRowAtIndexPath indexPath: NSIndexPath) {
print("Row \(indexPath.row) selected")
}

// 5
func tableView(tableView: UITableView, heightForRowAtIndexPath indexPath: NSIndexPath) -> CGFloat {
return 400
}





}




Answer

I hope this helps. I changed a couple small things around for better code (half could be considered bias). I think the issue is mostly that you were reloading the tableView in the loop. Everything else was just a slightly better way to handle this case. I put everything in viewDidLoad, and made the tableView load empty input prequel to receiving data. I think this is more standard for handling this scenario. If you need any other help let me know.

class ViewController: UIViewController {

    @IBOutlet var tableView: UITableView!

    var tableData: [String] = []
    var tableImages: [String] = []

    override func viewDidLoad() {
        super.viewDidLoad()

        if Reachability.isConnectedToNetwork() == true {
            var nib = UINib(nibName: "vwTblCell3", bundle: nil)
            tableView.registerNib(nib, forCellReuseIdentifier: "cell3")

            let request = NSURLRequest(URL: NSURL(string: "********.php")!)

            NSURLConnection.sendAsynchronousRequest(request, queue: NSOperationQueue(), completionHandler:{
                (response: NSURLResponse?, data: NSData?, error: NSError?)-> Void in

                let str2 = String(data: data!, encoding: NSUTF8StringEncoding)
                let str3 = Int(str2!)!
                let url = NSURL(string: "********")!

                let task = NSURLSession.sharedSession().dataTaskWithURL(url) { (data, response, error) -> Void in
                    if let urlContent = data {
                        do {
                            let jsonResult = try NSJSONSerialization.JSONObjectWithData(urlContent, options: NSJSONReadingOptions.MutableContainers)
                            self.tableData: [String] = []
                            self.tableImages: [String] = []  
                            for i in 0..<str3 {
                                self.tableData.append(jsonResult[i]["title"]! as! String)
                                self.tableImages.append(jsonResult[i]["image"]! as! String)
                            }

                            dispatch_async(dispatch_get_main_queue()) {
                                    self.tableView.reloadData()
                            }
                        } catch {
                            print("JSON serialization failed")
                        }
                    }
                }
                task.resume()
            });
        }
    }

    func tableView(tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
        return self.tableData.count
    }

    func tableView(tableView: UITableView, cellForRowAtIndexPath indexPath: NSIndexPath) -> UITableViewCell     {
        let cell: TblCell3 = self.tableView.dequeueReusableCellWithIdentifier("cell3") as! TblCell3
        cell.lblAffiliate.text = tableData[indexPath.row]


        let url3 = NSURL(string: "https://www.********.co.uk/\(tableImages[(indexPath as NSIndexPath).row]).png")
        cell.affiliateImage.sd_setImageWithURL(url3)

        return cell
    }

    func tableView(tableView: UITableView, didSelectRowAtIndexPath indexPath: NSIndexPath) {
        print("Row \(indexPath.row) selected")
    }

    func tableView(tableView: UITableView, heightForRowAtIndexPath indexPath: NSIndexPath) -> CGFloat {
        return 400
    }
}