MattBlack MattBlack - 1 month ago 24
Swift Question

UITableView Slow

I am new to Swift and have set up a tableView which pulls data from a JSON feed and loads it into the table.

The table loads fine however when there are more than say 10 cells in the table, it becomes slow and somewhat laggy, particularly it reaches the top and bottom (I imagine this is where a cell is being reused).

Would someone be so kind as to take a look at my code and explain why it may be doing this? I have implemented SDWebImage which has helped but its still not ideal:

var tableData = [String]()
var tableAvailable = [String]()
var tableImages = [String]()
var tableDesc = [String]()
var tablePin = [String]()

override func viewDidAppear(_ animated: Bool) {

let nib = UINib(nibName: "vwTblCell", bundle: nil)
tableView.register(nib, forCellReuseIdentifier: "cell")

self.tableData.removeAll(keepingCapacity: false)
self.tableAvailable.removeAll(keepingCapacity: false)
self.tableImages.removeAll(keepingCapacity: false)
self.tableDesc.removeAll(keepingCapacity: false)


let url = NSURL(string: "https://www.asmserver.co.uk/sally/parsexml.php")!
let task = URLSession.shared.dataTask(with: url as URL) { (data, response, error) -> Void in
if let urlContent = data {
do {

if let jsonResult = try JSONSerialization.jsonObject(with: urlContent, options: []) as? [[String:AnyObject]] {

for item in jsonResult {
guard let name = item["display-name"] as? String else { continue }

if (self.tableData.contains(item["display-name"] as! String)) {

}else{
self.tableData.append(name)

guard let available = item["status"] as? String else { continue }

self.tableAvailable.append(available)

guard let image = item["image-url"] as? String else { continue }

self.tableImages.append(image)

guard let desc = item["short-desc"] as? String else { continue }

self.tableDesc.append(desc)

guard let pin = item["agent-id"] as? String else { continue }

self.tablePin.append(pin)
}
}
}
} catch {
print("JSON serialization failed")
}
} else {
print("ERROR FOUND HERE")
}
DispatchQueue.main.async(execute: { () -> Void in
self.tableView.reloadData()
})
self.tableView.isUserInteractionEnabled = true
}
task.resume()
}

override func viewDidLoad() {

if revealViewController() != nil {
menuButton.addTarget(self.revealViewController(), action: #selector(SWRevealViewController.revealToggle(_:)), for: UIControlEvents.touchUpInside)
self.view.addGestureRecognizer(revealViewController().panGestureRecognizer())
}
}

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


// 3
func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
let cell: TblCell = self.tableView.dequeueReusableCell(withIdentifier: "cell") as! TblCell
cell.lblCarName.text = tableData[indexPath.row]

let url = NSURL(string: "\(tableImages[indexPath.row])")
if let data = NSData(contentsOf: url as! URL) {

cell.imgCarNane.sd_setImage(with: (string: url) as URL!)
}
cell.pinLabel.text = tablePin[indexPath.row]

if(tableAvailable[indexPath.row] == "Busy"){
cell.onlineIcon.image = UIImage(named: "livefeedofflineicon.png")
}
if (indexPath.row % 2 == 0){
cell.contentView.backgroundColor = UIColor(red: 237/255.0, green: 234/255.0, blue: 234/255.0, alpha: 1.0)
}

return cell
}

// 4
func tableView(_ tableView: UITableView, didSelectRowAt indexPath: IndexPath) {
print("Row \(indexPath.row) selected")
}

// 5
func tableView(_ tableView: UITableView, heightForRowAt indexPath: IndexPath) -> CGFloat {
return 140
}

Answer

I suppose in your cellForRowAt this line is making it a bit slow

if let data = NSData(contentsOf: url as! URL) {
    cell.imgCarNane.sd_setImage(with: (string: url) as URL!)
}

NSData(contentsOf: url as! URL) is making it a bit slow

Just remove the if let clause as SDWebImage handles the nil url itself and just write

cell.imgCarNane.sd_setImage(with: (string: url) as URL!)

So your cellForRowAt datasource method will become like this now

func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell  {
        let cell: TblCell = self.tableView.dequeueReusableCell(withIdentifier: "cell") as! TblCell
        cell.lblCarName.text = tableData[indexPath.row]

        let url = NSURL(string: "\(tableImages[indexPath.row])")
            cell.imgCarNane.sd_setImage(with: (string: url) as URL!)
               cell.pinLabel.text = tablePin[indexPath.row]

                if(tableAvailable[indexPath.row] == "Busy"){
                   cell.onlineIcon.image = UIImage(named: "livefeedofflineicon.png")
                }
                 if (indexPath.row % 2 == 0){
                cell.contentView.backgroundColor = UIColor(red: 237/255.0, green: 234/255.0, blue: 234/255.0, alpha: 1.0)
               }

        return cell
    }

I hope that fixes the lag