Getting Image from URL and append it to array - ios

I am trying to get images from a URL and append them to an array. This if my function for it:
func doStuff(html: String?){
do {
let doc: Document = try SwiftSoup.parse(html ?? "")
let priceClasses: Elements? = try doc.select("[class~=(?i)price]")
for priceClass: Element in priceClasses!.array() {
let priceText : String = try priceClass.text()
print(try priceClass.className())
print("pricetext: \(priceText)")
}
let srcs: Elements = try doc.select("img[src]")
let srcsStringArray: [String?] = srcs.array().map { try? $0.attr("src").description }
for imageName in srcsStringArray {
if (imageName?.matches("^https?://(?:[a-z0-9\\-]+\\.)+[a-z]{2,6}(?:/[^/#?]+)+\\.(?:jpg|gif|png)$"))! {
print(imageName!)
let imageView = UIImageView()
imageView.downloaded(from: imageName!) {
if let image = imageView.image {
self.imagesArray!.append(image)
} else {
print("Image '\(String(describing: imageName))' does not exist!")
}
}
}
}
} catch Exception.Error( _, let message) {
print(message)
} catch {
print("error")
}
}
This code is not working as it always exits and print <imageName> does not exist! . The weird thing is that the fileName is a correct name!
For example:
https://www.adidas.de/on/demandware.static/-/Sites-adidas-DE-Library/default/dw817801e3/Originals_Brand_Nav_Title.png
This is how I download the image from the URL:
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() {
self.image = image
}
}.resume()
}
func downloaded(from link: String, contentMode mode: UIView.ContentMode = .scaleAspectFit, finished: () -> Void) {
guard let url = URL(string: link) else { return }
downloaded(from: url, contentMode: mode)
finished()
}
}
Does anyone have any idea why I can not append images to my array ??? Im stuck..

I fixed the issue by changing the way I load the image:
extension UIImage {
public static func loadFrom(url: URL, completion: #escaping (_ image: UIImage?) -> ()) {
DispatchQueue.global().async {
if let data = try? Data(contentsOf: url) {
DispatchQueue.main.async {
completion(UIImage(data: data))
}
} else {
DispatchQueue.main.async {
completion(nil)
}
}
}
}
}
With this I simply call:
for imageName in srcsStringArray {
if (imageName?.matches("^https?://(?:[a-z0-9\\-]+\\.)+[a-z]{2,6}(?:/[^/#?]+)+\\.(?:jpg|gif|png)$"))! {
guard let url = URL(string: imageName!) else { return }
UIImage.loadFrom(url: url) { image in
if let image = image {
print("append")
self.imagesArray.append(image)
} else {
print("Image '\(String(describing: imageName))' does not exist!")
}
}
}
}

Related

get Image from local path in simulator

I'm trying to get the UIImage from the local URL, but it doesn't work.
My someURl, where data is NSSecureCoding?: file:///Users/a19468455/Library/Developer/CoreSimulator/Devices/2FA5B725-9266-429C-A036-256D846BC3FA/data/Media/PhotoData/OutgoingTemp/3F73D172-AA12-40AD-A3AB-540543A43330/IMG_0004.JPG
Here's what I've tried (sacrificed code styling for convenience):
guard let inputItems = extensionContext?.inputItems as? [NSExtensionItem else { return }
inputItems.forEach { item in
if let attachments = item.attachments,
!attachments.isEmpty {
attachments.forEach { attachment in
if attachment.hasItemConformingToTypeIdentifier(kUTTypeImage as String) {
var image: UIImage?
attachment.loadItem(forTypeIdentifier: kUTTypeImage as String, options: nil) { [weak self] data, error in
guard let self = self else { return }
guard error == nil else {
self.extensionContext!.completeRequest(returningItems: [], completionHandler: nil)
return
}
if let someURl = data as? URL {
do {
let data = try Data(contentsOf: someURl)
image = UIImage(data: data)
} catch {
print("failed to retrieve data")
}
}
if let image = image {
images.append(image)
}
}
}
}
}
}
I also tried tips from here without success:
how to load image from local path ios swift (by path)
how to load image from local image path Ios Swift 4
Loading/Downloading image from URL on Swift
I have no way to get Data from my link, how do I fix it?

Not able to get UIImage while downloading image. completionHandler(.notcompleted) getting called after guard let img = UIImage

func downloadImage(urlStr : String , completionHandler : #escaping (DownloadImage) -> Void) {
completionHandler(.serviceStarts)
DispatchQueue.global().async {
guard let url = URL(string: urlStr) else {
completionHandler(.notcompleted)
return
}
let dataTask = URLSession.shared.dataTask(with: url) { data, response, error in
guard let dt = data else{
completionHandler(.notcompleted)
return
}
guard let img = UIImage(data: dt) else {
completionHandler(.notcompleted)
return
}
completionHandler(.successful(img))
}
dataTask.resume()
}
}
enum DownloadImage {
case serviceStarts
case notcompleted
case successful(UIImage)
}

swift how to set button image from api

I'm trying to set an image on the button from API
here my code is
func collectionView(_ collectionView: UICollectionView, cellForItemAt indexPath: IndexPath) -> UICollectionViewCell {
let cell = collectionView.dequeueReusableCell(withReuseIdentifier: "Cell", for: indexPath) as! CreatGroupCollectionViewCell
cell.btn2.setImage(downloaded(link: String), for: .normal)
return cell
}
I also use an extension to download an image from the link
extension UIImageView {
func downloaded(from url: URL, contentMode mode: UIViewContentMode = .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: UIViewContentMode = .scaleAspectFit) {
guard let url = URL(string: link) else { return }
downloaded(from: url, contentMode: mode)
}
}
please tell me how to set an image on the button
Try using this extension to set image from url in a UIButton:
extension UIButton {
func setImageFrom(url link: String) {
guard let url = URL(string: link) else { return }
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?.setImage(image, for: .normal)
}
}.resume()
}
}
Use this extension to load image from url and store it to cache for faster reload.
let imageCache = NSCache<AnyObject, AnyObject>()
extension UIImageView {
func loadImageUsingCacheWithUrlString(_ urlString: String) {
self.image = nil
//check cache for image first
if let cachedImage = imageCache.object(forKey: urlString as AnyObject) as? UIImage {
self.image = cachedImage
return
}
//otherwise fire off a new download
guard let url = URL(string: "\(urlString)") else { return }
URLSession.shared.dataTask(with: url, completionHandler: { (data, response, error) in
//download hit an error so lets return out
if error != nil {
print(error ?? "")
return
}
DispatchQueue.main.async(execute: {
if let downloadedImage = UIImage(data: data!) {
imageCache.setObject(downloadedImage, forKey: urlString as AnyObject)
self.image = downloadedImage
}
})
}).resume()
}
}

TableView slow when adding images to cellForRowAtIndex [duplicate]

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.
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")
(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
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")
Xcode 12 • Swift 5
Leo Dabus's answer is awesome! I just wanted to provide an all-in-one function solution:
if 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()
}
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 ;)
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)
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 { [weak self] in
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")
With Cache support
let imageCache = NSCache<NSString, UIImage>()
extension UIImageView {
func loadImageUsingCacheWithURLString(_ URLString: String, placeHolder: UIImage?) {
self.image = nil
if let cachedImage = imageCache.object(forKey: NSString(string: URLString)) {
self.image = cachedImage
return
}
if let url = URL(string: URLString) {
URLSession.shared.dataTask(with: url, completionHandler: { (data, response, error) in
//print("RESPONSE FROM API: \(response)")
if error != nil {
print("ERROR LOADING IMAGES FROM URL: \(String(describing: error))")
DispatchQueue.main.async { [weak self] in
self?.image = placeHolder
}
return
}
DispatchQueue.main.async { [weak self] in
if let data = data {
if let downloadedImage = UIImage(data: data) {
imageCache.setObject(downloadedImage, forKey: NSString(string: URLString))
self?.image = downloadedImage
}
}
}
}).resume()
}
}
}
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")
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)
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!)
}
}
}
}
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
}
swift 5
extension UIImageView {
func load(url: URL) {
DispatchQueue.global().async { [weak self] in
if let data = try? Data(contentsOf: url) {
if let image = UIImage(data: data) {
DispatchQueue.main.async {
self?.image = image
}
}
}
}
}
}
for using
override func awakeFromNib() {
super.awakeFromNib()
if let url = URL(string:"<imageURLHere>"){
imgView.load(url: url)
}
}
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
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")
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
}
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)
Here is Working code for Loading / Downloading image from URL. NSCache automatically and Display Placeholder image before download and Load Actual image (Swift 4 | Swift 5 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 }
a quick hack if you want to quickly check image from url
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
}
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")
class ImageStore: NSObject {
static let imageCache = NSCache<NSString, UIImage>()
}
extension UIImageView {
func url(_ url: String?) {
DispatchQueue.global().async { [weak self] in
guard let stringURL = url, let url = URL(string: stringURL) else {
return
}
func setImage(image:UIImage?) {
DispatchQueue.main.async {
self?.image = image
}
}
let urlToString = url.absoluteString as NSString
if let cachedImage = ImageStore.imageCache.object(forKey: urlToString) {
setImage(image: cachedImage)
} else if let data = try? Data(contentsOf: url), let image = UIImage(data: data) {
DispatchQueue.main.async {
ImageStore.imageCache.setObject(image, forKey: urlToString)
setImage(image: image)
}
}else {
setImage(image: nil)
}
}
}
}
Usage :
let imageView = UIImageView()
imageView.url("image url")
AsyncImage is officially introduced after iOS 15, a view that synchronously loads and displays an image.
var imageView : AsyncImage
imageView = AsyncImage(url: URL(string: entry.photo))
.frame(width: 200, height: 200)
It also supports:
specify a custom placeholder using init(url:scale:content:placeholder:).
gain more control over the loading process, use the init(url:scale:transaction:content:)
See more in doc
Swift 4.1 I have created 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()
})
}
}
}
Edited for Latest change 09/2021
// It's better to use extension
extension UIImageView {
func downloadImage(from URLString: String, with completion: #escaping (_ response: (status: Bool, image: UIImage? ) ) -> Void) {
guard let url = URL(string: URLString) else {
completion((status: false, image: nil))
return
}
URLSession.shared.dataTask(with: url) { data, response, error in
guard error == nil else {
completion((status: false, image: nil))
return
}
guard let httpURLResponse = response as? HTTPURLResponse,
httpURLResponse.statusCode == 200,
let data = data else {
completion((status: false, image: nil))
return
}
let image = UIImage(data: data)
completion((status: true, image: image))
}.resume()
}
}
Happy Codding. Cheers:)
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.
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()
}
})
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)
}
})
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)
})
}
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.
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
}
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!)

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.
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")
(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
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")
Xcode 12 • Swift 5
Leo Dabus's answer is awesome! I just wanted to provide an all-in-one function solution:
if 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()
}
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 ;)
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)
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 { [weak self] in
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")
With Cache support
let imageCache = NSCache<NSString, UIImage>()
extension UIImageView {
func loadImageUsingCacheWithURLString(_ URLString: String, placeHolder: UIImage?) {
self.image = nil
if let cachedImage = imageCache.object(forKey: NSString(string: URLString)) {
self.image = cachedImage
return
}
if let url = URL(string: URLString) {
URLSession.shared.dataTask(with: url, completionHandler: { (data, response, error) in
//print("RESPONSE FROM API: \(response)")
if error != nil {
print("ERROR LOADING IMAGES FROM URL: \(String(describing: error))")
DispatchQueue.main.async { [weak self] in
self?.image = placeHolder
}
return
}
DispatchQueue.main.async { [weak self] in
if let data = data {
if let downloadedImage = UIImage(data: data) {
imageCache.setObject(downloadedImage, forKey: NSString(string: URLString))
self?.image = downloadedImage
}
}
}
}).resume()
}
}
}
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")
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)
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!)
}
}
}
}
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
}
swift 5
extension UIImageView {
func load(url: URL) {
DispatchQueue.global().async { [weak self] in
if let data = try? Data(contentsOf: url) {
if let image = UIImage(data: data) {
DispatchQueue.main.async {
self?.image = image
}
}
}
}
}
}
for using
override func awakeFromNib() {
super.awakeFromNib()
if let url = URL(string:"<imageURLHere>"){
imgView.load(url: url)
}
}
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
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")
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
}
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)
Here is Working code for Loading / Downloading image from URL. NSCache automatically and Display Placeholder image before download and Load Actual image (Swift 4 | Swift 5 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 }
a quick hack if you want to quickly check image from url
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
}
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")
class ImageStore: NSObject {
static let imageCache = NSCache<NSString, UIImage>()
}
extension UIImageView {
func url(_ url: String?) {
DispatchQueue.global().async { [weak self] in
guard let stringURL = url, let url = URL(string: stringURL) else {
return
}
func setImage(image:UIImage?) {
DispatchQueue.main.async {
self?.image = image
}
}
let urlToString = url.absoluteString as NSString
if let cachedImage = ImageStore.imageCache.object(forKey: urlToString) {
setImage(image: cachedImage)
} else if let data = try? Data(contentsOf: url), let image = UIImage(data: data) {
DispatchQueue.main.async {
ImageStore.imageCache.setObject(image, forKey: urlToString)
setImage(image: image)
}
}else {
setImage(image: nil)
}
}
}
}
Usage :
let imageView = UIImageView()
imageView.url("image url")
AsyncImage is officially introduced after iOS 15, a view that synchronously loads and displays an image.
var imageView : AsyncImage
imageView = AsyncImage(url: URL(string: entry.photo))
.frame(width: 200, height: 200)
It also supports:
specify a custom placeholder using init(url:scale:content:placeholder:).
gain more control over the loading process, use the init(url:scale:transaction:content:)
See more in doc
Swift 4.1 I have created 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()
})
}
}
}
Edited for Latest change 09/2021
// It's better to use extension
extension UIImageView {
func downloadImage(from URLString: String, with completion: #escaping (_ response: (status: Bool, image: UIImage? ) ) -> Void) {
guard let url = URL(string: URLString) else {
completion((status: false, image: nil))
return
}
URLSession.shared.dataTask(with: url) { data, response, error in
guard error == nil else {
completion((status: false, image: nil))
return
}
guard let httpURLResponse = response as? HTTPURLResponse,
httpURLResponse.statusCode == 200,
let data = data else {
completion((status: false, image: nil))
return
}
let image = UIImage(data: data)
completion((status: true, image: image))
}.resume()
}
}
Happy Codding. Cheers:)
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.
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()
}
})
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)
}
})
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)
})
}
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.
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
}
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!)

Resources