1

I am trying to load a couple images from a URL to my imageView but the way my code is set up, the app waits for the entire set of images to be downloaded and only then are the images displayed to the user. This causes a massive amount of waiting time once the application is opened.

To remove the waiting time, the images must be loaded to the imageView as soon as they are downloaded from the webURL, one by one. Could someone suggest how to do this?

Here is my code:

ViewController.swift

class ViewController: UIViewController , UICollectionViewDataSource {    

    @IBOutlet weak var collectionView: UICollectionView!

    let imageFetcher = ImageFetcher()

    var counter = 0

    override func viewDidLoad() {
        super.viewDidLoad()

        imageFetcher.setImageURL()
        NSTimer.scheduledTimerWithTimeInterval(01, target: self, selector: #selector(addCells), userInfo: nil, repeats: true)
        // Do any additional setup after loading the view, typically from a nib.
    }

    func addCells(timer : NSTimer){

        if(counter == imageFetcher.ImageArray.count){
            timer.invalidate()
            return
        }

        counter = counter + 1

        let indexPath = NSIndexPath(forItem: counter-1 , inSection: 0)
        collectionView.insertItemsAtIndexPaths([indexPath])
    }

    func collectionView(collectionView: UICollectionView, numberOfItemsInSection section: Int) -> Int {
        print("numberOfItemsInSection method just ran")                                                    //timeline indicator
        return counter    
    }      

    func collectionView(collectionView: UICollectionView, cellForItemAtIndexPath indexPath: NSIndexPath) -> UICollectionViewCell {

        let cell = collectionView.dequeueReusableCellWithReuseIdentifier("ImageCell", forIndexPath: indexPath) as! CollectionViewCell
        cell.imageView.image = imageFetcher.ImageArray[indexPath.row]
        return cell
    }
}

ImageFetcher.swift

class ImageFetcher {

    var newImage : UIImage?
    var ImageArray = [UIImage]()
    var imageURL : NSURL?{
        didSet{  newImage = nil
            Adder()
        }
    }

    func setImageURL(){
        imageURL = DemoURLs.randomImageUrl
    }    

    func fetchImage() {
        if let url = imageURL{
            let imageData = NSData(contentsOfURL: url)
            if imageData != nil{
                self.newImage  = UIImage( data: imageData! )
            } else {
                self.newImage = nil

            }
        }
    }

    func Adder(){
        for _ in 1...20 {

            fetchImage()
            ImageArray.append(newImage!)

        }
    } 
}
shim
  • 9,289
  • 12
  • 69
  • 108
209135
  • 517
  • 5
  • 15
  • 1
    You should be fetching images asynchronously (using `NSURLSession`) rather than synchronously (using `NSData(contentsOfURL:)`), and then in the completion handler, updating the UI as appropriate. Or, even better, find a `UIImageView` extension that supports asynchronous image retrieval, such as [AlamofireImage](https://github.com/Alamofire/AlamofireImage) or [KingFisher](https://github.com/onevcat/Kingfisher). – Rob Aug 09 '16 at 17:28
  • 1
    http://stackoverflow.com/questions/24231680/loading-downloading-image-from-url-on-swift/27712427#27712427 – Leo Dabus Aug 09 '16 at 18:23
  • Thanks for the suggestion. – 209135 Aug 11 '16 at 05:10

1 Answers1

2

You have to download the image when the cell is being displayed.

ImageFetcher.swift

class ImageFetcher {
    var images:[NSIndexPath: UIImage] = [:]
    func downloadImage(completion: (UIImage?)->Void) {
        let session = NSURLSession.sharedSession()
        if let url = self.imageURL {
            let imageURL = NSURL(string: url)

            let request = NSURLRequest(URL: imageURL!)

            let task = session.dataTaskWithRequest(request) {data, response, downloadError in

                if let imageData = data, image = UIImage(data: imageData) {
                    completion(image)
                } else {
                    completion(nil)
                }
            } 
            task.resume()
        } else {
            completion(nil)
        }

    }
}

ViewController.swift

func collectionView(collectionView: UICollectionView, cellForItemAtIndexPath indexPath: NSIndexPath) -> UICollectionViewCell {

    let cell = collectionView.dequeueReusableCellWithReuseIdentifier("ImageCell", forIndexPath: indexPath) as! CollectionViewCell

   cell.imageView.image = nil //or the placeholder image

   if let img = imageFetcher.images.valueForKey[indexPath] {
      cell.imageView.image = img
   } else {
      imageFetcher.downloadImage({ (image) in

            dispatch_async(dispatch_get_main_queue(), {
                if let img = image {
                    let c = collectionView.cellForItemAtIndexPath(indexPath) as! CollectionViewCell
                    c.imageView.image = img
                    imageFetcher.images[indexPath] = img
                } else {
                    print("Error!")
                }
            })

        })
   }


   return cell
}
LIH
  • 933
  • 2
  • 10
  • 25