Update table cell image asynchronously

2019-07-17 06:40发布

Im downloading the image link from a json and then creating the image once the table view start creating its cells:

 func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {

        let cell = tableView.dequeueReusableCell(withIdentifier: "cell", for: indexPath) as! TableViewCellController

            DispatchQueue.main.async(execute: { () -> Void in

                if let url = NSURL(string: self.movies[indexPath.row].image) 
                {

                    if let data = NSData(contentsOf: url as URL)
                    {
                        let imageAux = UIImage((data: data as Data))
                        cell.movieImage.image = imageAux
                        self.tableView.reloadData()

                    }
                }
            })

        cell.name = self.movies[indexPath.row].name
        cell.date = self.movies[indexPath.row].date
        return cell
}

And this works fine, but the table view becomes really slow, not at rendering but at scrolling. I keep checking the RAM and CPU and both are really low but my network use keeps rising BUT the images are already on the cell so it means its already done. (For this test im calling the JSON for only 2 movies, so 2 images)

Before i started doing this my total download was about 200kb (with images), now its getting over 2MB before i stop the project.

What im doing wrong?

1条回答
一夜七次
2楼-- · 2019-07-17 07:47

You'll probably want to designate a separate queue for background activities. In this instance, your heavy network task is in:

NSData(contentsOf: url as URL)

This is what is "freezing" the UI. The best solution would be to define something like DispatchQueue.background and perform the network calls there, while then later performing the UI tasks back on the main thread so as not to lock up your display:

DispatchQueue.background.async(execute: { () -> Void in
    if let url = NSURL(string: self.movies[indexPath.row].image)  {
        //Do this network stuff on the background thread
        if let data = NSData(contentsOf: url as URL) {
            let imageAux = UIImage(data: data as Data)
            //Switch back to the main thread to do the UI stuff
            DispatchQueue.main.async(execute: { () -> Void in
                cell.movieImage.image = imageAux
            })
        }
    }
})

Let me know if this makes sense.

查看更多
登录 后发表回答