Yuan Fu
Yuan Fu

Reputation: 308

Transform from NSData to UIImage very slow, block UITableView

I got NSData from Core Data, and when I transform from NSData to UIImage, it make my UITableView very slow to scroll. I already resize my Image before I store image to Core Data. Is there good way to do that. At first, I want to use Kingfisher, but it seems don't have this kind of method to achieve that.

override func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
    let cellIdentifier = "ListTableViewCell"

    guard let cell = tableView.dequeueReusableCell(withIdentifier: cellIdentifier, for: indexPath) as? ListTableViewCell  else {
        fatalError("The dequeued cell is not an instance of MealTableViewCell.")
    }
    //cell.imageContentPhoto.kf.setImage(with: url)
    cell.imageContentPhoto.image = UIImage(data: photos[indexPath.row] as Data)//photo is NSData, I got it from Core Data

return cell
}

Upvotes: 2

Views: 454

Answers (1)

Roy Falk
Roy Falk

Reputation: 1741

Your problem isn't that the transform is slow, but that it's done a lot of times when you scroll.

In order to optimize UITable, iOS does not create n cells for n rows. It creates x+2 cells (IIRC), where x is the number of visible cells.

When cellForRowAt is called, you call dequeueReusableCell, which takes one of the free cells and assigns it to the row. That way, when you scroll, there are no initializations of objects happening, and slowing the scrolling down.

The problem with your code (which is now evident), is that after the cell is allocated to the row, you again convert the image and initialize it.

What you should do is initialize the array of images in advance, for example in the viewDidLoad. Then your code would look like:

override func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
   let cellIdentifier = "ListTableViewCell"

   guard let cell = tableView.dequeueReusableCell(withIdentifier: cellIdentifier, for: indexPath) as? ListTableViewCell  else {
       fatalError("The dequeued cell is not an instance of MealTableViewCell.")
   }
   //cell.imageContentPhoto.kf.setImage(with: url)
   cell.imageContentPhoto.image = imagesArray[indexPath.row] // or something similar

  return cell
}

Of course, if you have a lot of different images, it might be worth doing some kind of lazy loading. Keep a place holder image while scrolling and when it stops, load the relevant images only. This is of course a lot more complicated and left as an exercise to the student.

Upvotes: 1

Related Questions