Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Faster way to load image from an URL to image view in table view cell

Tags:

xcode

ios

swift

I am using this to load URL to image view

let url = NSURL(string: URL)
let data = NSData(contentsOfURL: url!)
self.releasephoto.image  = UIImage(data: data!)

But when there is 10 items in table view cell with different images, scrolling gets slower and hangs

I load images with the size of 40 X 40

I wonder if there is a better way to load URL images ?

like image 488
Utku Dalmaz Avatar asked Mar 06 '15 18:03

Utku Dalmaz


3 Answers

I would suggest using SDWebImage.

After installing it you'll need to make a bridging header for Swift and include this line:

#import "UIImageView+WebCache.h"

Then all you need to do in your cellForRowAtIndexPath function is this:

let url = NSURL(string: URL)
self.releasephoto.sd_setImageWithURL(url)

The nice thing about this library is that it automatically caches the image so it's only downloaded once.

like image 95
Sam Avatar answered Nov 11 '22 00:11

Sam


You have to load the views asynchronously. Supply a dummy or blank image initially. Then load into your model, asynchronously in the background, any images for cells that are currently showing. As each image arrives, stash it in the model and reload the table view. Thus each image will appear when it happens to arrive, but your scrolling won't be slowed down because there always is an image - the blank or dummy if you have not fetched the image for this row, or the real image if you have fetched it.

Here's example code from my book:

override func tableView(tableView: UITableView, cellForRowAtIndexPath indexPath: NSIndexPath) -> UITableViewCell {
    let cell = tableView.dequeueReusableCellWithIdentifier("Cell", forIndexPath:indexPath) as UITableViewCell
    let m = self.model[indexPath.row]
    cell.textLabel!.text = m.text
    // have we got a picture?
    if let im = m.im {
        cell.imageView!.image = im
    } else {
        if m.task == nil { // no task? start one!
            cell.imageView!.image = nil
            m.task = self.downloader.download(m.picurl) { // *
                [weak self] url in // *
                m.task == nil // *
                if url == nil {
                    return
                }
                let data = NSData(contentsOfURL: url)!
                let im = UIImage(data:data)
                m.im = im
                dispatch_async(dispatch_get_main_queue()) {
                    self!.tableView.reloadRowsAtIndexPaths([indexPath], withRowAnimation: .None)
                }
            }
        }
    }
    return cell
}

(The full working example is here. And the code for MyDownloader, the class of self.downloader, is here.)

For extra super efficiency, cancel the download if the user scrolls a row out of view before the image arrives. That way you set a cap on how many downloads can be happening at once.

like image 5
matt Avatar answered Nov 11 '22 00:11

matt


I have already answered to the similar question here

Use the following class:

class ImageLoadingWithCache {

    var imageCache = [String:UIImage]()

    func getImage(url: String, imageView: UIImageView, defaultImage: String) {
        if let img = imageCache[url] {
            imageView.image = img
        } else {
            let request: NSURLRequest = NSURLRequest(URL: NSURL(string: url)!)
            let mainQueue = NSOperationQueue.mainQueue()

            NSURLConnection.sendAsynchronousRequest(request, queue: mainQueue, completionHandler: { (response, data, error) -> Void in
                if error == nil {
                    let image = UIImage(data: data)
                    self.imageCache[url] = image

                    dispatch_async(dispatch_get_main_queue(), {
                        imageView.image = image
                    })
                }
                else {
                    imageView.image = UIImage(named: defaultImage)
                }
            })
        }
    }
}

Usage:

var cache = ImageLoadingWithCache()
cache.getImage(YOUR_URL, imageView: YOUR_IMAGEVIEW, defaultImage: "DEFAULT_IMAGE_NAME")
like image 5
Kalpesh Avatar answered Nov 11 '22 00:11

Kalpesh