By QuentR


2014-06-15 16:27:05 8 Comments

I'd like to load an image from a URL in my application, so I first tried with Objective-C and it worked, however, with Swift, I've a compilation error:

'imageWithData' is unavailable: use object construction 'UIImage(data:)'

My function:

@IBOutlet var imageView : UIImageView

override func viewDidLoad() {
    super.viewDidLoad()

    var url:NSURL = NSURL.URLWithString("http://myURL/ios8.png")
    var data:NSData = NSData.dataWithContentsOfURL(url, options: nil, error: nil)

    imageView.image = UIImage.imageWithData(data)// Error here
}

In Objective-C:

- (void)viewDidLoad {
    [super viewDidLoad];

    NSURL *url = [NSURL URLWithString:(@"http://myURL/ios8.png")];
    NSData *data = [NSData dataWithContentsOfURL:url];

    _imageView.image = [UIImage imageWithData: data];
    _labelURL.text = @"http://www.quentinroussat.fr/assets/img/iOS%20icon's%20Style/ios8.png";
 }

Can someone please explain me why the imageWithData: doesn't work with Swift, and how can I solve the problem.

30 comments

@Leo Dabus 2014-12-30 20:55:00

Xcode 8 or later • Swift 3 or later

Synchronously:

if let filePath = Bundle.main.path(forResource: "imageName", ofType: "jpg"), let image = UIImage(contentsOfFile: filePath) {
    imageView.contentMode = .scaleAspectFit
    imageView.image = image
}

Asynchronously:

Create a method with a completion handler to get the image data from your url

func getData(from url: URL, completion: @escaping (Data?, URLResponse?, Error?) -> ()) {
    URLSession.shared.dataTask(with: url, completionHandler: completion).resume()
}

Create a method to download the image (start the task)

func downloadImage(from url: URL) {
    print("Download Started")
    getData(from: url) { data, response, error in
        guard let data = data, error == nil else { return }
        print(response?.suggestedFilename ?? url.lastPathComponent)
        print("Download Finished")
        DispatchQueue.main.async() {
            self.imageView.image = UIImage(data: data)
        }
    }
}

Usage:

override func viewDidLoad() {
    super.viewDidLoad()
    // Do any additional setup after loading the view, typically from a nib.
    print("Begin of code")
    let url = URL(string: "https://cdn.arstechnica.net/wp-content/uploads/2018/06/macOS-Mojave-Dynamic-Wallpaper-transition.jpg")! 
    downloadImage(from: url)
    print("End of code. The image will continue downloading in the background and it will be loaded when it ends.")
}

Extension:

extension UIImageView {
    func downloaded(from url: URL, contentMode mode: UIViewContentMode = .scaleAspectFit) {  // for swift 4.2 syntax just use ===> mode: UIView.ContentMode
        contentMode = mode
        URLSession.shared.dataTask(with: url) { data, response, error in
            guard
                let httpURLResponse = response as? HTTPURLResponse, httpURLResponse.statusCode == 200,
                let mimeType = response?.mimeType, mimeType.hasPrefix("image"),
                let data = data, error == nil,
                let image = UIImage(data: data)
                else { return }
            DispatchQueue.main.async() {
                self.image = image
            }
        }.resume()
    }
    func downloaded(from link: String, contentMode mode: UIViewContentMode = .scaleAspectFit) {  // for swift 4.2 syntax just use ===> mode: UIView.ContentMode
        guard let url = URL(string: link) else { return }
        downloaded(from: url, contentMode: mode)
    }
}

Usage:

imageView.downloaded(from: "https://cdn.arstechnica.net/wp-content/uploads/2018/06/macOS-Mojave-Dynamic-Wallpaper-transition.jpg")

@EI Captain v2.0 2015-05-04 04:17:34

what if i want to use alamofire to load url of image...

@Jase 2015-06-04 14:39:18

I'm curious, why do you do completion(data: NSData(data: data)) instead of just completion(data: data)?

@Leo Dabus 2015-06-04 16:36:57

@Jase there is no need. Just data it is fine

@Paul Peelen 2015-08-02 22:25:22

Just a side note here, you should set an associated object to it; Otherwise you might load images on top of each other. E.g. in a UITableView where a cell shows an image and the image is updated when the dequeued cell is returned. If process #1 takes longer then process #2, process #2 will show its image and it will then later be updated by process #1 even though that image is no longer valid for the user.

@siarheibrazil 2015-09-11 10:00:10

I think that it's necessary to return operation from the method: getDataFromUrl. It gives opportunity to cancel scheduled operation.

@BigBoy1337 2015-10-16 20:10:11

Is this supposed to work if there is no image? For instance If I give it a url which returns an (s3 no such key error), it simply replaces my image with nothing. I think the data in this case is the error report. Is there a way to additionally check that the data returned is an image file?

@Nasir Khan 2015-12-10 10:46:13

how to use last function in button?

@jo3birdtalk 2016-02-07 03:42:25

hi, I'm using your extension to implement, and I think my image is not displaying because my UIImage is inside a tableview, and i think i need to refresh the table. Do you know where and how should i implement this refresh?

@Leo Dabus 2016-02-07 04:10:24

@jo3birdtalk you are not using my extension, you are using NSURLConnection. You don't have to refresh anything

@jo3birdtalk 2016-02-07 04:41:56

@LeoDabus May i refer you to my post, as I'm unsure if I'm implementing your codes correctly. stackoverflow.com/questions/35248864/how-to-update-image-vie‌​w

@AndHeiberg 2016-02-08 11:25:24

@PaulPeelen could you add more info about how this would be done? It would be great if we could make this awesome answer even better.

@Paul Peelen 2016-02-08 12:49:55

@AndHeiberg Check objc_setAssociatedObject and objc_removeAssociatedObjects.

@AndHeiberg 2016-02-08 21:43:53

@PaulPeelen I did, but it's not the clearest of concepts. Right now I don't have an issue with it so I'm not gonna try and grok it. But it would seem you have the experience so just thought it would be epic if you appended to the answer.

@JengGe Chao 2016-03-07 12:07:07

This solved me my problem. When I try to load image with url in table view, scroll view is really not responding when scroll to top or down. I used UIImageView Extension and it solved my problem. Thanks.

@Crashalot 2016-04-20 19:13:14

@PaulPeelen couldn't you solve the UITableView problem also by using if let cellToUpdate = tableView.cellForRowAtIndexPath(indexPath) { cellToUpdate.imageView?.image = image }? If the cell is no longer visible then the image won't get updated and therefore won't overwrite anything.

@Leo Dabus 2016-04-20 19:26:40

@Crashalot it is an old comment. Just use the UIImageView extension

@Crashalot 2016-04-20 19:48:17

@LeoDabus ok thanks. and thanks for answering so many questions on SO! you're like a professor of swift and iOS. :)

@Crashalot 2016-04-20 19:52:05

@LeoDabus btw do you happen to know the answer to this question? stackoverflow.com/questions/36728704/…

@Crashalot 2016-04-20 21:13:37

@LeoDabus how come you used dataTaskWithURL instead of downloadTaskWithURL?

@Leo Dabus 2016-04-20 21:48:10

The first one downloads to memory the second one to a file

@Michael Yaworski 2016-08-06 04:14:22

How do I use URL and .scaleAspectFit and URLSession? Are those imports? Which ones?

@Leo Dabus 2016-08-06 05:41:05

@Minas 2017-01-23 00:05:38

@LeoDabus Hey, great solution, can you please explain how it is safe from race condition when used in tableview? Also is there a way to limit "file cache" size? ( e.g. 5 mb )

@JCarlos 2017-03-07 00:03:35

It works well but the last imagenes of a tableView don't load. The images that are not visible initially, don't load after scroll.

@Tom Tallak Solbu 2018-06-28 15:11:28

when I try, I get: "Thread 1: Fatal error: Unexpectedly found nil while unwrapping an Optional value", pointing to : imageView.downloadedFrom(link: "apple.com/euro/ios/ios8/a/generic/images/og.png"). Wy does this not work?

@Leo Dabus 2018-08-27 14:45:58

@TomTallakSolbu have you checked if your image view it is properly connected to your view controller or custom cell?

@Honey 2018-10-21 22:15:14

The code works fine. Just that when I do po UIImage(data:data) in the debugger it returns nil. Yet in the app, the image is loaded. I'm not sure if there's it's a bug with Xcode or something...

@Leo Dabus 2018-10-21 22:16:51

@Honey You need to provide more context on your issue. Are you sure that your data object is a valid image?

@Honey 2018-10-22 00:06:29

Doesn't the fact that the image loads on the screen mean that it's a valid image?

@Rizwan Ahmed 2018-12-11 09:44:17

This approach will fail unless you handle async calls properly.

@Leo Dabus 2018-12-11 10:00:05

@RizwanAhmed Any approach would fail if you don't know how to handle async calls properly.

@Rizwan Ahmed 2018-12-11 10:06:58

@LeoDabus : Implement this code snippet in a UITableViewCell, it should be able to handle multiple requests properly. The current code doesn't. That is what I meant.

@Leo Dabus 2018-12-11 10:08:38

The OP didn't ask how to handle multiple calls in a table view. He is clearly using a single image view in his question. Feel free open a new question and post your issue.

@Neela 2018-12-21 17:32:23

This is so much helpful. Thanks.

@Hamid Shahsavari 2019-01-09 21:15:21

Swift 4.2 and AlamofireImage

If using a library is not an issue, you can do it by help of the AlamofireImage. my samples are from its Github

Placeholder Images Example:

let imageView = UIImageView(frame: frame)
let url = URL(string: "https://httpbin.org/image/png")!
let placeholderImage = UIImage(named: "placeholder")!
imageView.af_setImage(withURL: url, placeholderImage: placeholderImage)

it has many handy functions and extension to work with images. from caching to scaling and resizing or even applying filters on the image. if images are important in your app, I suggest to use this framework and save your time.

@Abhimanyu Rathore 2019-01-02 23:18:40

Image loading from server :-

func downloadImage(from url: URL , success:@escaping((_ image:UIImage)->()),failure:@escaping ((_ msg:String)->())){
    print("Download Started")
    getData(from: url) { data, response, error in
        guard let data = data, error == nil else {
            failure("Image cant download from G+ or fb server")
            return
        }

        print(response?.suggestedFilename ?? url.lastPathComponent)
        print("Download Finished")
        DispatchQueue.main.async() {
             if let _img = UIImage(data: data){
                  success(_img)
            }
        }
    }
}
func getData(from url: URL, completion: @escaping (Data?, URLResponse?, Error?) -> ()) {
    URLSession.shared.dataTask(with: url, completionHandler: completion).resume()
}

Usage :-

  if let url = URL(string: "http://www.apple.com/euro/ios/ios8/a/generic/images/og.png") {
                        self.downloadImage(from:url , success: { (image) in
                            print(image)

                        }, failure: { (failureReason) in
                            print(failureReason)
                        })
                    }

@Shruti Thombre 2018-10-10 10:21:42

You can use pod SDWebImage to achieve the same. Its easy to use. Yo can get documentaion here SDWebImage

Here is the sample code

self.yourImage.sd_setImage(with: NSURL(string: StrUrl as String ) as URL!, placeholderImage: placeholderImage, options: SDWebImageOptions(rawValue: 0), completed: { (image, error, cacheType, imageURL) in
                if( error != nil)
                {
                    print("Error while displaying image" , (error?.localizedDescription)! as String)
                }
            })

@Raj Salla 2018-09-27 10:23:17

I recommend using Kingfisher library to download images asynchronously. The best part about using Kingfisher is, it caches all the downloaded images by default with the image url as an id. Next time when you request to download image with that particular URl, it will load it from cache.

Usage:

newsImage.kf.setImage(with: imageUrl!, placeholder: nil, options: nil, progressBlock: nil, completionHandler: { (image, error, cacheType, imageUrl) in
                if error == nil{
                    self.activityIndicator.stopAnimating()
                }else if error != nil{
                    self.activityIndicator.stopAnimating()
                }
            })

@Jack 2018-09-14 10:40:17

Swift 4::

This will shows loader while loading the image. You can use NSCache which store image temporarily

let imageCache = NSCache<NSString, UIImage>()
extension UIImageView {
    func loadImageUsingCache(withUrl urlString : String) {
        let url = URL(string: urlString)
        if url == nil {return}
        self.image = nil

        // check cached image
        if let cachedImage = imageCache.object(forKey: urlString as NSString)  {
            self.image = cachedImage
            return
        }

        let activityIndicator: UIActivityIndicatorView = UIActivityIndicatorView.init(activityIndicatorStyle: .gray)
        addSubview(activityIndicator)
        activityIndicator.startAnimating()
        activityIndicator.center = self.center

        // if not, download image from url
        URLSession.shared.dataTask(with: url!, completionHandler: { (data, response, error) in
            if error != nil {
                print(error!)
                return
            }

            DispatchQueue.main.async {
                if let image = UIImage(data: data!) {
                    imageCache.setObject(image, forKey: urlString as NSString)
                    self.image = image
                    activityIndicator.removeFromSuperview()
                }
            }

        }).resume()
    }
}

Usage:-

truckImageView.loadImageUsingCache(withUrl: currentTruck.logoString)

@djdance 2019-04-21 11:54:29

It works. Just copy activityIndicator removal in error case too.

@Vishal16 2018-09-11 08:44:49

class func downloadImageFromUrl(with urlStr: String, andCompletionHandler:@escaping (_ result:Bool) -> Void) {
        guard let url = URL(string: urlStr) else {
            andCompletionHandler(false)
            return
        }
        DispatchQueue.global(qos: .background).async {
            URLSession.shared.dataTask(with: url, completionHandler: { (data, response, error) -> Void in
                if error == nil {
                    let httpURLResponse = response as? HTTPURLResponse
                    Utils.print( "status code ID : \(String(describing: httpURLResponse?.statusCode))")
                    if httpURLResponse?.statusCode == 200 {
                        if let data = data {
                            if let image = UIImage(data: data) {
                                ImageCaching.sharedInterface().setImage(image, withID: url.absoluteString as NSString)
                                DispatchQueue.main.async {
                                    andCompletionHandler(true)
                                }
                            }else {
                                andCompletionHandler(false)
                            }
                        }else {
                            andCompletionHandler(false)
                        }
                    }else {
                        andCompletionHandler(false)
                    }
                }else {
                    andCompletionHandler(false)
                }
            }).resume()
        }
    }

I have created a simple class function in my Utils.swift class for calling that method you can simply accesss by classname.methodname and your images are saved in NSCache using ImageCaching.swift class

Utils.downloadImageFromUrl(with: URL, andCompletionHandler: { (isDownloaded) in
                            if isDownloaded {
                                if  let image = ImageCaching.sharedInterface().getImage(URL as NSString) {
                                    self.btnTeam.setBackgroundImage(image, for: .normal)
                                }
                            }else {
                                DispatchQueue.main.async {
                                    self.btnTeam.setBackgroundImage(#imageLiteral(resourceName: "com"), for: .normal)
                                }
                            }
                        })

Happy Codding. Cheers:)

@GSK 2018-08-19 14:53:53

Swift 4.1 I have crated a function just pass image url, cache key after image is generated set it to completion block.

   class NetworkManager: NSObject {

  private var imageQueue = OperationQueue()
  private var imageCache = NSCache<AnyObject, AnyObject>()

  func downloadImageWithUrl(imageUrl: String, cacheKey: String, completionBlock: @escaping (_ image: UIImage?)-> Void) {

    let downloadedImage = imageCache.object(forKey: cacheKey as AnyObject)
    if let  _ = downloadedImage as? UIImage {
      completionBlock(downloadedImage as? UIImage)
    } else {
      let blockOperation = BlockOperation()
      blockOperation.addExecutionBlock({
        let url = URL(string: imageUrl)
        do {
          let data = try Data(contentsOf: url!)
          let newImage = UIImage(data: data)
          if newImage != nil {
            self.imageCache.setObject(newImage!, forKey: cacheKey as AnyObject)
            self.runOnMainThread {
              completionBlock(newImage)
            }
          } else {
            completionBlock(nil)
          }
        } catch {
          completionBlock(nil)
        }
      })
      self.imageQueue.addOperation(blockOperation)
      blockOperation.completionBlock = {
        print("Image downloaded \(cacheKey)")
      }
    }
  }
}
extension NetworkManager {
  fileprivate func runOnMainThread(block:@escaping ()->Void) {
    if Thread.isMainThread {
      block()
    } else {
      let mainQueue = OperationQueue.main
      mainQueue.addOperation({
        block()
      })
    }
  }
}

@Nikunj Kumbhani 2018-08-08 12:15:51

Here is Working code for Loading / Downloading image from URL. NSCache automatically and Display Placeholder image before download and Load Actual image (Swift 4 Code).

func NKPlaceholderImage(image:UIImage?, imageView:UIImageView?,imgUrl:String,compate:@escaping (UIImage?) -> Void){

    if image != nil && imageView != nil {
        imageView!.image = image!
    }

    var urlcatch = imgUrl.replacingOccurrences(of: "/", with: "#")
    let documentpath = NSSearchPathForDirectoriesInDomains(.documentDirectory, .userDomainMask, true)[0]
    urlcatch = documentpath + "/" + "\(urlcatch)"

    let image = UIImage(contentsOfFile:urlcatch)
    if image != nil && imageView != nil
    {
        imageView!.image = image!
        compate(image)

    }else{

        if let url = URL(string: imgUrl){

            DispatchQueue.global(qos: .background).async {
                () -> Void in
                let imgdata = NSData(contentsOf: url)
                DispatchQueue.main.async {
                    () -> Void in
                    imgdata?.write(toFile: urlcatch, atomically: true)
                    let image = UIImage(contentsOfFile:urlcatch)
                    compate(image)
                    if image != nil  {
                        if imageView != nil  {
                            imageView!.image = image!
                        }
                    }
                }
            }
        }
    }
}

Use Like this :

// Here imgPicture = your imageView
// UIImage(named: "placeholder") is Display image brfore download and load actual image. 

NKPlaceholderImage(image: UIImage(named: "placeholder"), imageView: imgPicture, imgUrl: "Put Here your server image Url Sting") { (image) in }

@iGhost 2018-09-07 18:34:12

that work for me, thanks.

@Nikunj Kumbhani 2018-09-08 04:37:54

@iGhost Happy to help.... if satisfied with answer don't forget to accept it :)

@fethica 2018-02-16 18:37:50

Swift 4: A simple loader for small images (ex: thumbnails) that uses NSCache and always runs on the main thread:

class ImageLoader {

  private static let cache = NSCache<NSString, NSData>()

  class func image(for url: URL, completionHandler: @escaping(_ image: UIImage?) -> ()) {

    DispatchQueue.global(qos: DispatchQoS.QoSClass.background).async {

      if let data = self.cache.object(forKey: url.absoluteString as NSString) {
        DispatchQueue.main.async { completionHandler(UIImage(data: data as Data)) }
        return
      }

      guard let data = NSData(contentsOf: url) else {
        DispatchQueue.main.async { completionHandler(nil) }
        return
      }

      self.cache.setObject(data, forKey: url.absoluteString as NSString)
      DispatchQueue.main.async { completionHandler(UIImage(data: data as Data)) }
    }
  }

}

Usage:

ImageLoader.image(for: imageURL) { image in
  self.imageView.image = image
}

@XcodeNOOB 2018-03-25 07:20:47

Why use singleton with struct ? this will cause your class to be immutable which can cause issues with your NSCache

@fethica 2018-03-25 16:41:38

Thanks for pointing this out, I've just changed it to class.

@Hammad Tariq 2018-05-14 08:25:02

private let cache was giving me error so changed it to static and it worked! Thanks

@saurabh rathod 2018-07-05 11:36:42

Use of Ascyimageview you can easy load imageurl in imageview.

let image1Url:URL = URL(string: "(imageurl)" as String)! imageview.imageURL = image1Url

@Kamani Jasmin 2018-04-13 21:13:06

Kingfisher is one of the best library for load image into URL.

Github URL - https://github.com/onevcat/Kingfisher

// If you want to use Activity Indicator.
imageview_pic.kf.indicatorType = .activity
imageview_pic.kf.setImage(with: URL(string: "Give your url string"))

// If you want to use custom placeholder image.
imageview_pic.kf.setImage(with: URL(string: "Give your url string"), placeholder: UIImage(named: "placeholder image name"), options: nil, progressBlock: nil, completionHandler: nil)

@Manee ios 2017-03-29 06:56:21

swift 3 with error handling

let url = URL(string: arr[indexPath.row] as! String)
if url != nil {
    DispatchQueue.global().async {
        let data = try? Data(contentsOf: url!) //make sure your image in this url does exist, otherwise unwrap in a if let check / try-catch
        DispatchQueue.main.async {
            if data != nil {
                cell.imgView.image = UIImage(data:data!)
            }else{
                cell.imgView.image = UIImage(named: "default.png")
            }
        }
    }
}

With Extension

extension UIImageView {

    func setCustomImage(_ imgURLString: String?) {
        guard let imageURLString = imgURLString else {
            self.image = UIImage(named: "default.png")
            return
        }
        DispatchQueue.global().async {
            let data = try? Data(contentsOf: URL(string: imageURLString)!)
            DispatchQueue.main.async {
                self.image = data != nil ? UIImage(data: data!) : UIImage(named: "default.png")
            }
        }
    }
}

Extension Usage

myImageView. setCustomImage("url")

@Mark Moeykens 2016-09-23 17:18:49

Xcode 8Swift 3

Leo Dabus's answer is awesome! I just wanted to provide an all-in-one function solution:

let url = URL(string: 
    "http://www.apple.com/euro/ios/ios8/a/generic/images/og.png")

let task = URLSession.shared.dataTask(with: url!) { data, response, error in
    guard let data = data, error == nil else { return }

    DispatchQueue.main.async() {    // execute on main thread
        self.imageView.image = UIImage(data: data)
    }
}

task.resume()

@Fattie 2017-01-03 17:49:05

Mark, probably meant "async" at the end there

@Lucas Eduardo 2014-12-17 02:08:38

(Swift 4 update) To answer the original question directly, here's the swift equivalent of the posted Objective-C snippet.

let url = URL(string: image.url)
let data = try? Data(contentsOf: url!) //make sure your image in this url does exist, otherwise unwrap in a if let check / try-catch
imageView.image = UIImage(data: data!)

DISCLAIMER:

It's important to note that the Data(contentsOf:) method will download the contents of the url synchronously in the same thread the code is being executed, so do not invoke this in the main thread of your application.

An easy way to make the same code run asynchronously, not blocking the UI, is by using GCD:

let url = URL(string: image.url)

DispatchQueue.global().async {
    let data = try? Data(contentsOf: url!) //make sure your image in this url does exist, otherwise unwrap in a if let check / try-catch
    DispatchQueue.main.async {
        imageView.image = UIImage(data: data!)
    }
}

That said, in real life applications, if you want to have the best User Experience and avoid multiple downloads of the same image, you may want to also have them not only downloaded, but cached. There's already quite a few libraries that does that very seamless and they are all really easy to use. I personally recommend Kingfisher:

import Kingfisher

let url = URL(string: "url_of_your_image")
// this downloads the image asynchronously if it's not cached yet
imageView.kf.setImage(with: url) 

And that's it

@Orlin Georgiev 2015-04-16 08:00:50

"Easily" is subjective, and novice coders won't expect this unwanted behaviour, but copy/paste this snipped as it is. Perhaps you can update your answer?

@Lucas Eduardo 2015-04-17 01:36:36

I still do not agree. Some answers should be kept simple, a lot of people that comes here likes to copy and paste small snippets of code. I just translated to Swift the objective-C code from the original question, everything besides that is a bonus. And by the way, there is already a answer in this same question providing this kind of bonus information, which makes less sense to duplicate information.

@User 2016-03-29 03:40:06

Can you change your example to use an actual URL string? What is the variable image with the url property?

@Lucas Eduardo 2016-03-29 08:41:16

@User just replace the image.url by any string url, hardcoded or not :)

@Jason Sturges 2016-07-21 20:29:37

Reference to property imageView in closure requires explicit self. to make capture semantics explicit: self.imageView.image = UIImage()

@Lucas Eduardo 2016-07-22 08:54:24

@JasonSturges if your imageView is a property, yes, you should use .self first. This was a generic example

@Ian Warburton 2016-08-04 15:27:28

This works but why not use URLSession.dataTask?

@Lucas Eduardo 2016-08-05 15:17:00

@IanWarburton Of course you can use whatever you want :). 1) This answer is based in the original question, which was using the same approach in objective-C, so I just helped in the "translation" to swift. 2) It doesn't make sense to remove this approach and put the URLSession.dataTask because a lot of other answers here already show how to do it, It's better to keep the different options opened.

@Ian Warburton 2016-08-05 15:50:13

@LucasEduardo Is URLSession likely to be implemented using GCD?

@Lucas Eduardo 2016-08-09 09:25:01

@IanWarburton the URLSession is most likely to be implemented with NSOperations and NSOperationQueus, which are indeed built on top of GCD. So I guess your answer is yes

@Fattie 2017-01-03 17:29:13

In this argument, Lucas is perfectly correct.

@Lucas Eduardo 2017-01-22 02:41:04

@CouchDeveloper and why exactly is the code poor? Would love to know your reasons :)

@CouchDeveloper 2017-01-22 11:35:22

@LucasEduardo First I apologise for being just rude and lazy. :/ But this is my opinion on the quality of the answer. Even though many novice OPs do like an overly simplified code snippet that's copy&past without having to read about their misconceptions and having to know about the invalid assumptions which must be fulfilled in order the solution "to work". What I and probably others would like to see is an explanation and better code. See Leo's answer for example - which is not short and simple and not copy&paste - but far better.

@Lucas Eduardo 2017-01-23 17:26:53

@CouchDeveloper I see your point but... Leo's answer is very good indeed, but also lack any explanation, only contains code. Which is fine, since the original question didn't ask for any. About the code quality, you are assuming that using NSURLSession is better than using the Data's init async, which in this specific case I don't see many advantages (would love to argue with more characters). In the real world, besides downloading the image, you also need a proper cache mechanism and for that a library to handle everything is the best choice anyways. So, don't overreact something simple :)

@Lucas Eduardo 2017-01-23 17:27:34

@CouchDeveloper And again, the whole point is keep different options opened and available, it helps in the learning also. No need to repeat things that are already in other answers.

@Above The Gods 2017-12-12 02:35:01

I vote to have this reply removed as it is certainly not the correct way to do it. Why Apple hasn't removed the ability to perform synchronous network requests is beyond me.

@Lucas Eduardo 2017-12-12 10:03:52

@AboveTheGods I indeed certainly do not recommend the usage of the posted snippet in real life applications, I posted it right after the question was made, simply helping the OP in translating his Obj-C code to Swift. Since the question got quite good ranked on google after some time, I updated my answer to contain a disclaimer and recommend the best approach

@Kilmazing 2019-03-15 21:06:29

Heyo, the suggested framework, kingfisher, as stated in the answer will do all of the heavy lifting. Thanks for the suggestion!

@Bobby 2017-04-30 09:17:09

Swift 4

This method will download an image from a website asynchronously and cache it:

    func getImageFromWeb(_ urlString: String, closure: @escaping (UIImage?) -> ()) {
        guard let url = URL(string: urlString) else {
return closure(nil)
        }
        let task = URLSession(configuration: .default).dataTask(with: url) { (data, response, error) in
            guard error == nil else {
                print("error: \(String(describing: error))")
                return closure(nil)
            }
            guard response != nil else {
                print("no response")
                return closure(nil)
            }
            guard data != nil else {
                print("no data")
                return closure(nil)
            }
            DispatchQueue.main.async {
                closure(UIImage(data: data!))
            }
        }; task.resume()
    }

In use:

    getImageFromWeb("http://www.apple.com/euro/ios/ios8/a/generic/images/og.png") { (image) in
        if let image = image {
            let imageView = UIImageView(frame: CGRect(x: 0, y: 0, width: 200, height: 200))
            imageView.image = image
            self.view.addSubview(imageView)
        } // if you use an Else statement, it will be in background
    }

@Ramis 2017-11-27 04:14:59

How it is caching? And for how long?

@Bobby 2017-11-27 13:30:18

It seems to be permanently stored, which is weird, it is stored in the Library>Caches folder. Use print(NSHomeDirectory()) to get to this location on your computer when run on the simulator.

@FARAZ 2017-06-15 11:24:46

For Swift-3 and above:

extension UIImageView {
  public func imageFromUrl(urlString: String) {
    if let url = URL(string: urlString) {
        let request = URLRequest(url: url)
        NSURLConnection.sendAsynchronousRequest(request as URLRequest, queue: .main, completionHandler: { (response, data, error) in
            if let imageData = data as NSData? {
                self.image = UIImage(data: imageData as Data)
            }
        })
    }
  }
}

@Cody 2016-06-22 03:35:05

Swift 2 with error Handle and custom request header

Simply add extension to UIImageView:

extension UIImageView {
    public func imageFromUrl(urlString: String) {
        if let url = NSURL(string: urlString) {
            let request = NSMutableURLRequest(URL: url)
            request.setValue("<YOUR_HEADER_VALUE>", forHTTPHeaderField: "<YOUR_HEADER_KEY>")
            NSURLSession.sharedSession().dataTaskWithRequest(request) {
                (data, response, error) in
                guard let data = data where error == nil else{
                    NSLog("Image download error: \(error)")
                    return
                }

                if let httpResponse = response as? NSHTTPURLResponse{
                    if httpResponse.statusCode > 400 {
                        let errorMsg = NSString(data: data, encoding: NSUTF8StringEncoding)
                        NSLog("Image download error, statusCode: \(httpResponse.statusCode), error: \(errorMsg!)")
                        return
                    }
                }

            dispatch_async(dispatch_get_main_queue(), {
                NSLog("Image download success")
                self.image = UIImage(data: data)
            })
            }.resume()
        }
    }
}

And then, use the new imageFromUrl(urlString: String) to download image

Usage:

imageView.imageFromUrl("https://i.imgur.com/ONaprQV.png")

@Aymen BRomdhane 2016-09-20 09:43:32

in swift 3 , I keep getting this error . What's the problem ? In this line """ URLSession.shared.dataTask(with: url){""""""" Cannot invoke 'dataTask' with an argument list of type '(with: URL, (Data?, URLResponse?, Error?) -> Void)'

@Naishta 2016-04-27 21:58:58

If you are looking for a very very simple implementation. (This worked for me in Swift 2)

 let imageURL = NSURL(string: "https://farm2.staticflickr.com/1591/26078338233_d1466b7da2_m.jpg")
 let imagedData = NSData(contentsOfURL: imageURL!)!
 imageView?.image = UIImage(data: imagedData)

I implemented within a tableview with a custom cell that has only a image

func tableView(tableView: UITableView, cellForRowAtIndexPath indexPath: NSIndexPath) -> UITableViewCell{

        let cell = tableView.dequeueReusableCellWithIdentifier("theCell", forIndexPath: indexPath) as! customTableViewCell

        let imageURL = NSURL(string: "https://farm2.staticflickr.com/1591/26078338233_d1466b7da2_m.jpg")

        let imagedData = NSData(contentsOfURL: imageURL!)!

        cell.imageView?.image = UIImage(data: imagedData)

        return cell

    }

@Gourav Joshi 2016-10-13 05:36:25

Yes It will be work, but it is very slowest one....

@Naishta 2016-10-13 20:52:19

you are right , thats because downloading and compressing is happening on the main thread. you should ideally do these 2 steps asynchronously in a background thread, may be using dispatch_async global queue

@Gourav Joshi 2016-10-14 04:12:05

Yes, By using background thread we can optimize the speed of downloading and If required we can change the logic instead of this we can use sdWebImage or other framework.

@Crashalot 2016-04-21 19:57:24

Swift 2.x answer that downloads image to file (as opposed to Leo Dabus's answer, which stores the image in memory). Based on Leo Dabus's answer and Rob's answer from Get the data from NSURLSession DownloadTaskWithRequest from completion handler:

    // Set download vars
    let downloadURL = NSURL() // URL to download from
    let localFilename = "foobar.png" // Filename for storing locally 

    // Create download request
    let task = NSURLSession.sharedSession().downloadTaskWithURL(downloadURL) { location, response, error in
        guard location != nil && error == nil else {
            print("Error downloading message: \(error)")
            return
        }

        // If here, no errors so save message to permanent location
        let fileManager = NSFileManager.defaultManager()
        do {
            let documents = try fileManager.URLForDirectory(.DocumentDirectory, inDomain: .UserDomainMask, appropriateForURL: nil, create: false)
            let fileURL = documents.URLByAppendingPathComponent(localFilename)
            try fileManager.moveItemAtURL(location!, toURL: fileURL)
            self.doFileDownloaded(fileURL, localFilename: localFilename)
            print("Downloaded message @ \(localFilename)")
        } catch {
            print("Error downloading message: \(error)")
        }
    }

    // Start download
    print("Starting download @ \(downloadURL)")
    task.resume()


// Helper function called after file successfully downloaded
private func doFileDownloaded(fileURL: NSURL, localFilename: String) {

    // Do stuff with downloaded image

}

@Bibin Joseph 2016-04-19 10:56:58

Use this code in Swift

imageView.image=UIImage(data: NSData(contentsOfURL: NSURL(string: "http://myURL/ios8.png")!)!

@swiftBoy 2016-03-29 14:57:23

Swift 2.2 || Xcode 7.3

I got Amazing results!! with AlamofireImage swift library

It provides multiple features like:

  • Asynchronously download
  • Auto Purging Image Cache if memory warnings happen for the app
  • Image URL caching
  • Image Caching
  • Avoid Duplicate Downloads

and very easy to implement for your app

Step.1 Install pods


Alamofire 3.3.x

pod 'Alamofire'

AlamofireImage 2.4.x

pod 'AlamofireImage'

Step.2 import and Use

import Alamofire
import AlamofireImage

let downloadURL = NSURL(string: "http://cdn.sstatic.net/Sites/stackoverflow/company/Img/photos/big/6.jpg?v=f4b7c5fee820")!
imageView.af_setImageWithURL(downloadURL)

that's it!! it will take care everything


Great thanks to Alamofire guys, for making iDevelopers life easy ;)

@thejuki 2016-10-12 01:00:56

Swift 3: foregroundImage.af_setImage(withURL: downloadURL as URL)

@A.G 2016-02-17 05:31:57

Swift 2.0 :

1)

if let url = NSURL(string: "http://etc...") {
    if let data = NSData(contentsOfURL: url) {
        imageURL.image = UIImage(data: data)
    }        
}

OR

imageURL.image =
    NSURL(string: "http:// image name...")
    .flatMap { NSData(contentsOfURL: $0) }
    .flatMap { UIImage(data: $0) }

2) Add this method to VC or Extension.

func load_image(urlString:String)
{   let imgURL: NSURL = NSURL(string: urlString)!
    let request: NSURLRequest = NSURLRequest(URL: imgURL)

    NSURLConnection.sendAsynchronousRequest(request, queue: NSOperationQueue.mainQueue()) { (response: NSURLResponse?, data: NSData?, error: NSError?) in

        if error == nil {
            self.image_element.image = UIImage(data: data)
        }
    }
}

Usage :

self.load_image(" url strig here")

@Crashalot 2016-04-20 20:16:39

sendAsynchronousRequest is deprecated in iOS 9

@skywinder 2015-06-02 09:11:02

If you just want to load image (Asynchronously!) - just add this small extension to your swift code:

extension UIImageView {
    public func imageFromUrl(urlString: String) {
        if let url = NSURL(string: urlString) {
            let request = NSURLRequest(URL: url)
            NSURLConnection.sendAsynchronousRequest(request, queue: NSOperationQueue.mainQueue()) {
                (response: NSURLResponse?, data: NSData?, error: NSError?) -> Void in
                if let imageData = data as NSData? {
                    self.image = UIImage(data: imageData)
                }
            }
        }
    }
}

And use it this way:

myImageView.imageFromUrl("https://robohash.org/123.png")

@alex 2015-10-25 22:08:20

change data to imageData in last line to make code more copy-pastable=)

@skywinder 2015-10-26 06:52:05

@alex thanks, done!

@jo3birdtalk 2016-02-07 03:13:23

It is not showing up, and I think because there is a need for GCD. How do I refresh?

@skywinder 2016-02-08 07:04:53

@jo3birdtalk it's not a problem of GCD. Check your bindings with view.

@muhasturk 2016-03-11 02:18:34

NSURLConnection is deprecated on iOS 9 and so on. Use NSURLSession intead.

@Crashalot 2016-04-20 20:14:48

sendAsynchronousRequest is deprecated in iOS 9

@ZAFAR007 2016-07-19 05:59:56

Thanks skywinder, I am using this method for downloading images from array. I want when user press on cancel button it stops downloading. Have you any idea how i can do this with using this method? I've need to add cancel functionality.

@skywinder 2018-08-26 18:18:49

@muhasturk thanks for update. I'm not ios developer anymore. feel free to edit and update my answer!

@Karsten 2019-01-11 09:58:11

the code is outdated in Swift 4.2. it never stops...

@Ben Patch 2015-12-08 17:28:52

A method for getting the image that is safe and works with Swift 2.0 and X-Code 7.1:

static func imageForImageURLString(imageURLString: String, completion: (image: UIImage?, success: Bool) -> Void) {
    guard let url = NSURL(string: imageURLString),
        let data = NSData(contentsOfURL: url),
        let image = UIImage(data: data)
        else { 
            completion(image: nil, success: false); 
            return 
       }

    completion(image: image, success: true)
}

You would then call this method like so:

imageForImageURLString(imageString) { (image, success) -> Void in
        if success {
            guard let image = image 
                 else { return } // Error handling here 
            // You now have the image. 
         } else {
            // Error handling here.
        }
    }

If you are updating the view with the image, you will have to use this after the "if success {":

    dispatch_async(dispatch_get_main_queue()) { () -> Void in
         guard let image = image 
              else { return } // Error handling here 
         // You now have the image. Use the image to update the view or anything UI related here
         // Reload the view, so the image appears
    }

The reason this last part is needed if you are using the image in the UI is because network calls take time. If you try to update the UI using the image without calling dispatch_async like above, the computer will look for the image while the image is still being fetched, find that there is no image (yet), and move on as if there was no image found. Putting your code inside of a dispatch_async completion closure says to the computer, "Go, get this image and when you are done, then complete this code." That way, you will have the image when the code is called and things will work well.

@datayeah 2015-03-09 12:43:32

I wrapped the code of the best answers to the question into a single, reusable class extending UIImageView, so you can directly use asynchronous loading UIImageViews in your storyboard (or create them from code).

Here is my class:

import Foundation
import UIKit

class UIImageViewAsync :UIImageView
{

    override init()
    {
        super.init(frame: CGRect())
    }

    override init(frame:CGRect)
    {
        super.init(frame:frame)
    }

    required init(coder aDecoder: NSCoder) {
        super.init(coder: aDecoder)
    }

    func getDataFromUrl(url:String, completion: ((data: NSData?) -> Void)) {
        NSURLSession.sharedSession().dataTaskWithURL(NSURL(string: url)!) { (data, response, error) in
            completion(data: NSData(data: data))
        }.resume()
    }

    func downloadImage(url:String){
        getDataFromUrl(url) { data in
            dispatch_async(dispatch_get_main_queue()) {
                self.contentMode = UIViewContentMode.ScaleAspectFill
                self.image = UIImage(data: data!)
            }
        }
    }
}

and here is how to use it:

imageView.downloadImage("http://www.image-server.com/myImage.jpg")

@S. Ferit Arslan 2015-05-28 13:20:58

class initializer must be changed. super.init(frame: CGRect()) for the non parameter instance

@datayeah 2015-11-02 14:27:46

thanks, i updated it.

@NYC Tech Engineer 2016-04-19 03:18:17

Do we really need those overridden inits? Aren't the inits inherited anyway? Seems like we're just overriding here just to call super on itself, which strikes me as redundant.

@katopz 2015-07-13 06:05:55

FYI : For swift-2.0 Xcode7.0 beta2

extension UIImageView {
    public func imageFromUrl(urlString: String) {
        if let url = NSURL(string: urlString) {
            let request = NSURLRequest(URL: url)
            NSURLConnection.sendAsynchronousRequest(request, queue: NSOperationQueue.mainQueue()) {
            (response: NSURLResponse?, data: NSData?, error: NSError?) -> Void in
                self.image = UIImage(data: data!)
            }
        }
    }
}

@BilalReffas 2015-09-03 19:38:29

NSURLConnection is depracated. You have to use NSURLSession. It's better when you code with Swift 2.0 and Xcode 7

@Simon Jensen 2014-11-03 13:00:57

The only things there is missing is a !

let url = NSURL.URLWithString("http://live-wallpaper.net/iphone/img/app/i/p/iphone-4s-wallpapers-mobile-backgrounds-dark_2466f886de3472ef1fa968033f1da3e1_raw_1087fae1932cec8837695934b7eb1250_raw.jpg");
var err: NSError?
var imageData :NSData = NSData.dataWithContentsOfURL(url!,options: NSDataReadingOptions.DataReadingMappedIfSafe, error: &err)
var bgImage = UIImage(data:imageData!)

@Simon Jensen 2017-05-23 17:19:55

Sorry for the late reply, could you be more precise on what errors you get?

@user3763002 2014-06-21 14:14:01

let url = NSURL.URLWithString("http://live-wallpaper.net/iphone/img/app/i/p/iphone-4s-wallpapers-mobile-backgrounds-dark_2466f886de3472ef1fa968033f1da3e1_raw_1087fae1932cec8837695934b7eb1250_raw.jpg");
var err: NSError?
var imageData :NSData = NSData.dataWithContentsOfURL(url,options: NSDataReadingOptions.DataReadingMappedIfSafe, error: &err)
var bgImage = UIImage(data:imageData)

@User 2014-09-13 00:37:03

fatal error: unexpectedly found nil while unwrapping an Optional value

@Jed Grant 2014-10-15 21:43:17

Any chance you can write up something asynchronous?

@code ninja 2014-10-29 20:53:08

@JedGrant you could use dispatch_async to get into another thread and a callback

@botbot 2014-11-29 22:51:26

I had to unwrap the NSData with an "!" (note the ! at the end) to get it work like this: var imageData :NSData = NSData(contentsOfURL: url, options: NSDataReadingOptions.DataReadingMappedIfSafe, error: &err)!

@joshstaiger 2014-06-15 16:51:15

You’ll want to do:

UIImage(data: data)

In Swift, they’ve replaced most Objective C factory methods with regular constructors.

See:

https://developer.apple.com/library/prerelease/ios/documentation/Swift/Conceptual/BuildingCocoaApps/InteractingWithObjective-CAPIs.html#//apple_ref/doc/uid/TP40014216-CH4-XID_26

@Brian Nickel 2014-06-16 16:44:20

Technically mapped, not replaced. If you make your own method +(instancetype)[MyThing thingWithOtherThing:], you would call it as MyThing(otherThing: ...) in Swift too.

Related Questions

Sponsored Content

19 Answered Questions

[SOLVED] #pragma mark in Swift?

  • 2014-06-03 14:05:56
  • Arbitur
  • 205841 View
  • 880 Score
  • 19 Answer
  • Tags:   swift

32 Answered Questions

[SOLVED] Split a String into an array in Swift?

16 Answered Questions

[SOLVED] How to call Objective-C code from Swift

  • 2014-06-02 20:05:42
  • David Mulder
  • 263871 View
  • 904 Score
  • 16 Answer
  • Tags:   objective-c swift

6 Answered Questions

[SOLVED] How to get image from UIImagePickerController and Pass to next VC

  • 2015-06-01 13:14:59
  • MilkBottle
  • 8396 View
  • 0 Score
  • 6 Answer
  • Tags:   ios swift

9 Answered Questions

[SOLVED] Swift Beta performance: sorting arrays

9 Answered Questions

[SOLVED] How to detect tableView cell touched or clicked in swift

3 Answered Questions

[SOLVED] Swift Error - Use of undeclared type 'cell' - Collection View

5 Answered Questions

[SOLVED] Xcode 6 error 'URLWithString' is unavailable?

3 Answered Questions

Swift 2 iOS 9 animation disappears after button text changed

  • 2015-08-10 09:11:34
  • nepete
  • 1137 View
  • 1 Score
  • 3 Answer
  • Tags:   ios swift2

1 Answered Questions

How do you get an image from a "t.co" URL (Twitter specific images) for an iOS app?

Sponsored Content