skip to Main Content

I want to create UIImage(urlString: String?). There is no error when I run this code but it is not working.

extension UIImage {
    convenience init?(urlString: String?) { 
        var imageData = Data()
        guard let urlString = urlString else { return nil}
        guard let url = URL(string: urlString) else { return nil}
        URLSession.shared.dataTask(with: url) { data, response, error in
            if let error = error {
                print("Error: (error.localizedDescription)")
                return
            }
            guard let response = response as? HTTPURLResponse else {
                print("Empty image response")
                return
            }
            print("HTTP image response code: (response.statusCode)")
            guard let data = data else {
                print("Empty image data")
                return
            }
            imageData = data
        }.resume()
        self.init(data: imageData)
    }
}

2

Answers


  1. UIImage initializer init(data:) is a synchronous method. Your self.init(data: imageData) method is called before the async method dataTask finish its request and execute its completion handler.

    What I suggest is to create an instance method extending URL and add a completion handler to it:

    extension URL {
        func asyncImage(completion: @escaping (UIImage?) -> Void) {
            URLSession.shared.dataTask(with: self) { data, _, _ in
                guard let data = data, let image = UIImage(data: data) else {
                    completion(nil)
                    return
                }
                completion(image)
            }.resume()
        }
    }
    

    Usage:

    yourURL.asyncImage { image in 
        guard let image = image else { return }
        // use image here
    }
    

    Another option is to extend UIImageView as shown in this post

    Login or Signup to reply.
  2. My solution for you:

    • Use Data(contentsOf:URL) to get Data from an URL, instead of using URLSession.dataTask
       extension UIImage {  
        convenience init?(urlString: String) {
            self.init()
            guard let url = URL(string: urlString), let data = try? Data(contentsOf: url) else { return }
            self.init(data: data)
        }
    }
    

    You have to call self.init() because it required self.init() to be called before return.
    Because this is a Failable Initializer, if your URL is valid then you get an image from that URL, otherwise, you get nil.

    In case you want to use a default image when your URL is invalid, just replace init() with init(named:):

       extension UIImage {  
        convenience init?(urlString: String) {
            self.init(named: "YOUR_IMAGE_NAME")
            guard let url = URL(string: urlString), let data = try? Data(contentsOf: url) else { return }
            self.init(data: data)
        }
    }
    
    Login or Signup to reply.
Please signup or login to give your own answer.
Back To Top
Search