Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Loading/Downloading image from URL on Swift

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.

like image 404
QuentR Avatar asked Jun 15 '14 16:06

QuentR


People also ask

How do I download an image from a URL?

Click on the Download Image from URL button, the field will appear on the right. Enter the full web address of the image. Click on the arrow to the right of the field and select the Force Check checkbox. Then click the Save button.

How do I download an image from URL SwiftUI?

Using AsyncImage to download remote imagesstruct ContentView: View { var body: some View { AsyncImage(url: URL(string: "https://picsum.photos/200/300")!) } } The above code results in a random fetched image every time the view appears: Downloading and caching an image in SwiftUI is an everyday use case.

How do I import an image into Swift?

First one is to drag and drop an image file from Finder onto the assets catalog. Dragging the image will automatically create new image set for you. Drag and drop image onto Xcode's assets catalog. Or, click on a plus button at the very bottom of the Assets navigator view and then select “New Image Set”.

How do I display an image in Swift UI?

To display an image, simply add the image file into your asset library (Assets. xcassets) and then pass the name of the asset as a string to your Image element in Line 1.


2 Answers

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")         // always update the UI from the main thread         DispatchQueue.main.async() { [weak self] in             self?.imageView.image = UIImage(data: data)         }     } } 

Usage:

override func viewDidLoad() {     super.viewDidLoad()     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: 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: 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") 
like image 161
Leo Dabus Avatar answered Sep 18 '22 18:09

Leo Dabus


(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

like image 36
Lucas Eduardo Avatar answered Sep 20 '22 18:09

Lucas Eduardo