Loading/Downloading image from URL on Swift

前端 未结 30 2566
感动是毒
感动是毒 2020-11-21 05:39

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:

相关标签:
30条回答
  • 2020-11-21 05:54

    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() { [weak self] in
                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: UIView.ContentMode = .scaleAspectFit) {
            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() { [weak self] in
                    self?.image = image
                }
            }.resume()
        }
        func downloaded(from link: String, contentMode mode: UIView.ContentMode = .scaleAspectFit) { 
            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")
    
    0 讨论(0)
  • 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")
    
    0 讨论(0)
  • 2020-11-21 05:55

    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()
                    }
                })
    
    0 讨论(0)
  • 2020-11-21 05:56

    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
    }
    
    0 讨论(0)
  • 2020-11-21 05:56

    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")
    
    0 讨论(0)
  • 2020-11-21 05:57

    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.

    0 讨论(0)
提交回复
热议问题