3

I've been trying to create a photo gallery in Swift 3.0 and I want to load images stored in the document directory into the collection view asynchronously. I tried DispatchQueue.main.async but it blocks the main thread and freezes the app for a few seconds:

func collectionView(_ collectionView: UICollectionView, cellForItemAt indexPath: IndexPath) -> UICollectionViewCell {
    let identifier = "ImageCell"
    let cell = collectionView.dequeueReusableCell(withReuseIdentifier: identifier, for: indexPath) as! ImageCell
    let url = self.imageURL[indexPath.row]
    cell.lazyLoadImage(from: url)
    return cell
}

And the ImageCell class:

class ImageCell: UICollectionViewCell {
    @IBOutlet weak var imageView: UIImageView!

    func lazyLoadImage(from url: URL) {
        DispatchQueue.main.async {
            if let image = UIImage(contentsOfFile: url.path) {
                self.imageView.image = image
            }
        }
    }
}

I appreciate your help. Thank you.

rmaddy
  • 314,917
  • 42
  • 532
  • 579
Jake A.
  • 540
  • 5
  • 12
  • If you pause the app while it's frozen, what's in the main thread's backtrace? – Charles Srstka Nov 03 '18 at 04:36
  • Actually you are doing nothing i mean you are in main thread and also dispatch block in main thread – SPatel Nov 03 '18 at 04:53
  • If the images are just files, I wouldn't have thought you would need to dispatch anything asynchronously; just load the image. If your image files are really large, consider have thumbnails that load more quickly in your cells. – Paulw11 Nov 03 '18 at 09:25

2 Answers2

6

First switch to background thread and load image on it, and again switch to main thread and display image.

func lazyLoadImage(from url: URL) {
     DispatchQueue.global(qos: .userInteractive).async {
         if let image = UIImage(contentsOfFile: url.path) {
             DispatchQueue.main.async {
                 self.imageView.image = image
             }
         }
    }
}
SPatel
  • 4,768
  • 4
  • 32
  • 51
0

You are doing it completing wrong. In short, I can say that's not the "lazy loading". What you are doing is blocking the threads to download the content from the URL and load it to UIImageView. The thread will not be release until the download happens and you are using it in "reusable Cells" and that's obvious your application will stuck!

Solution

There are many most popular libraries like AlamofireImage, SDWebImage , Kingfisher. From which I am picking up "SDWebImage" and you can call load image in async way via following code:

imageView.sd_setImage(with: url , placeholderImage: nil)

Also, please refer to this SO question (how to implement lazy loading of images in table view using swift) for more detail.

Sohil R. Memon
  • 9,404
  • 1
  • 31
  • 57