1

I have an issue with my table view being choppy on scroll while it loads each image inside the function of cellForItemAtIndexPath i've searched through some examples and these are the things i've tried and still have the same issue.

So i have this

var arrRes = [[String:AnyObject]]()

Then inside view did load i make an Alamofire GET request and with swiftyJSON i store the json file to the above dictionary.

if let resData = swiftyJsonVar["events"].arrayObject {
  self.arrRes = resData as! [[String:AnyObject]]
}
self.tableview2.reloadData()




func numberOfSectionsInTableView(tableView: UITableView) -> Int {

    return 1

}


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

    return arrRes.count
}



func tableView(tableView: UITableView, cellForRowAtIndexPath indexPath: NSIndexPath) -> UITableViewCell {

    let cell = tableView.dequeueReusableCellWithIdentifier("mapCell", forIndexPath: indexPath) as! locationEventsTableViewCell

    var dict = arrRes[indexPath.row]

    cell.eventTitle.text = dict["eventName"] as? String

    let cal = dict["eventStarttime"] as? String



    let dateF = NSDateFormatter()
    dateF.dateFormat = "yyyy-MM-dd'T'HH:mm:ssZ"
    let date:NSDate = dateF.dateFromString(cal!)!


    let d = NSDateFormatter()

    d.dateFormat = "dd-MM-yyyy HH:mm"
    let d1 = d.stringFromDate(date)
    cell.eventDate.text = d1
    let at = dict["eventStats"]?["attendingCount"] as? Int
    let kapa = at?.stringValue
    cell.eventAttends.text = kapa
    let imageDef : UIImage = UIImage(named: "noimage")!


    let priority = DISPATCH_QUEUE_PRIORITY_DEFAULT
    dispatch_async(dispatch_get_global_queue(priority, 0)) {
    if let theImage = dict["eventCoverPicture"] as? String {

        let url = NSURL(string: theImage)

        if url != nil {
            let data = NSData(contentsOfURL: url!)
            dispatch_async(dispatch_get_main_queue()) {
            cell.eventImage.image = UIImage(data: data!)

            }

        } else {
            cell.eventImage.image = imageDef
        }


    }
    }



    return cell

}

So as you can see i am using the dispatch async function to get the image and even if i have it or not its still choppy.

Has anyone any solution about this? Thanks!

Konstantinos Natsios
  • 2,874
  • 9
  • 39
  • 74

2 Answers2

2

So the problem is that you're calling the images from a URL each time your UITableView is showing. Every time the cell goes off screen and comes back it's calling the method to retrieve the image from the server.

The server calls are being performed while the UI is trying to execute, this includes the scrolling and other visual loads.

Depending on the app, you can download all the images for the UITableView before you load the tableView and store them locally. I would also look into NSCache as that might be better for your app.

The goal is to have UI always be the number one priority. So if there are things that need to be in the UITableView like your eventCoverPicture, load them or call them from memory before you load the UITableView.

  1. This ensures you're making the minimum amount of server calls necessary to reduce user network load.

  2. The UI is interrupted and your users can scroll through their app without this choppiness.

  • You are right. This is a long term solution though until i find out how to do it but at least the data are loaded only once in the beginning so i guess im in a good way. Although thank you for your guideline!! – Konstantinos Natsios Jul 22 '16 at 20:31
  • And if you want to not store locally but just load them every time you load the ViewController you can use a `UIActivityIndicatorView` to show the user you're loading data from a server before you formally present the UITableView. –  Jul 22 '16 at 20:32
  • You think it would be a good idea to show one default image (or a loading image) until the image is actually shown in the cell? I think now its getting a bit better! – Konstantinos Natsios Jul 22 '16 at 20:34
  • 1
    SDWebImage is a great library for handling image url loading and caches them to memory automatically. It also a has prefetcher so if the total number of image urls the tableview might display is impractical to prefetch all at once, you can lazy load the next few cells in the list. There also methods which accept arguments for setting a placeholder image – markedwardmurray Jul 22 '16 at 20:36
1

I think your code is right about Async api. it's possibly the NSDateFormatter slowing you down. Date formatter is an heavy API. Use memorization, it would improve the prformance as well.

class MyObject {

    // define static variable

    private static let formatter: NSDateFormatter = {
        let formatter = NSDateFormatter()
        formatter.dateFormat = "EEE MMM dd HH:mm:ss Z yyyy"
        return formatter
    }()

    // you could use it like so

    func someMethod(date: NSDate) -> String {

        return MyObject.formatter.stringFromDate(date)
    }
}
Kunal Balani
  • 4,739
  • 4
  • 36
  • 73