0

My UICollectionView is fetching images in cellForItemAt. After I upgrade to swift 3, some images are not showing when I scroll very fast. Here is my code in cellForItemAt:

if (imageNotInCache) {
    DispatchQueue.global(qos: DispatchQoS.QoSClass.default).async {
    if let thumb = imageFromPathAndCacheIt(path) {
      DispatchQueue.main.async {
          let updateCell = collectionView.cellForItem(at: indexPath) as! MyCustomCell? {
             updateCell.imageView.image = thumb
          }
   }
}

The problem is, sometimes I get updateCell as nil even it is on the screen (probably because scroll to fast).

I know we can add reloadData after adding the image, just like: Swift 3: Caching images in a collectionView, but I don't want to call reload so many times.

Thank you for interested in this question. Any ideas would be very appreciated!

Community
  • 1
  • 1
Lucy.W
  • 51
  • 1
  • 5

1 Answers1

1

There's definitely a compromise between accessing and manually updating the cell view content, and calling reloadData on the whole collection view that you could try.

You can use the func reloadItems(at: [IndexPath]) to ask the UICollectionView to reload a single cell if it's on screen.

Presumably, imageNotInCache means you're storing image in an in-memory cache, so as long as image is also accessible by the func collectionView(UICollectionView, cellForItemAt: IndexPath), the following should "just work":

if (imageNotInCache) {
    DispatchQueue.global(qos: DispatchQoS.QoSClass.default).async {
        if let thumb = imageFromPathAndCacheIt(path) {
            DispatchQueue.main.async {
                self.collectionView.reloadItems(at: [indexPath])
            }
        }
    }
}
TiM
  • 15,812
  • 4
  • 51
  • 79
  • Thanks for your answer! This can make all images be shown in correct cells . But the thing is now scrolling for the first time becomes jerky... I wonder if there is a way to just get the right cell for updating? – Lucy.W Dec 15 '16 at 14:20
  • No worries! Hmm, without knowing more about how your app works, I'm not sure! You might need to use Instruments to see exactly what's blocking the main thread while scrolling. Just in case you're not doing this, simply creating a `UIImage` on a background thread won't decode the image into memory; that'll happen lazily when the image view comes on screen. This can usually cause most scroll view lag. There's a lot of questions on SO on how to explicitly force a `UIImage` to decode ahead of time in the background: http://stackoverflow.com/questions/3904575/decode-images-in-background-thread – TiM Dec 15 '16 at 20:04
  • There's also a lot of optimizations you can do in general to improve scroll performance: https://medium.com/ios-os-x-development/perfect-smooth-scrolling-in-uitableviews-fd609d5275a5#.t8tw7ojhp – TiM Dec 15 '16 at 20:05
  • Hey thanks for the links, they are very helpful! What I did in my code is that I download all the images beforehand (which a very big), and in `cellForItem` I resize each into a smaller size and put into cache. It might sound weird but that is what i need to do. – Lucy.W Dec 16 '16 at 14:35