'I can't make extension convenience init for UIImage
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)
}
}
Solution 1:[1]
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)
}
}
Solution 2:[2]
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
Sources
This article follows the attribution requirements of Stack Overflow and is licensed under CC BY-SA 3.0.
Source: Stack Overflow
Solution | Source |
---|---|
Solution 1 | |
Solution 2 |