Reputation: 17591
I need to load an image from a url and set it inside an UIImageView; the problem is that I don't know the exact size of the image, then how can I show the image correctly?
Upvotes: 55
Views: 91691
Reputation: 763
Swift safe code version:
private func loadImage(from url:URL) -> UIImage? {
let imageData: Data
do {
imageData = try Data(contentsOf: url)
} catch {
return nil
}
return UIImage(data: imageData)
}
private func loadImage(from urlString:String) -> UIImage? {
guard let url = URL(string: urlString) else {
return nil
}
return self.loadImage(from: url)
}
Keep in mind that this code blocks the main thread, so you should run it on a background thread. For example:
DispatchQueue.global().async {
let image = UIImage(fromFile: "http://xpto.com/image.png")
// And then you should update UI on main thread.
// If you have an UIImageView outlet you can update its image this way:
DispatchQueue.main.async {
imageView.image = image
imageView.contentMode = .scaleAspectFit
}
}
Upvotes: 1
Reputation: 763
If you prefer you can even move it to an UIImage
extension:
extension UIImage {
//NOTE: This is not thread safe, please run it on a background thread.
convenience init?(fromFile filePath:String) {
guard let url = URL(string: filePath) else {
return nil
}
self.init(fromURL: url)
}
//NOTE: This is not thread safe, please run it on a background thread.
convenience init?(fromURL url:URL) {
let imageData: Data
do {
imageData = try Data(contentsOf: url)
} catch {
return nil
}
self.init(data: imageData)
}
}
Upvotes: 0
Reputation: 991
One common mistake in displaying an image downloaded from json or a url is the problem of queues. ALL UI-related things need to be done in the main queue, so if you forgot this, even perfect code (above answers are good) won't display your image on occasion. To call the mainQueue, use code like this, and note that calling main queue might need to be done seperately in the called imageDisplay function:
dispatch_async(dispatch_get_main_queue(), ^{
self.nameLabel.text = self.pokemon.name;
[self displayImage]; //CALLS FUNCTION
self.abilitiesTextView.text = @"loves SwiftUI";
});
- (void)displayImage {
NSString *imageURLString = [NSString stringWithFormat: self.pokemon.sprite];
NSData *imageData = [[NSData alloc] initWithContentsOfURL:[NSURL URLWithString:imageURLString]];
dispatch_async(dispatch_get_main_queue(), ^{
self.spriteImageView.image = [UIImage imageWithData: imageData];
});
// NOTE: important for newer versions of XCode/Obj-C...
//[imageData release]; With ARC ("automated release..."), release method is forbidden, it's already done for you.
}
Upvotes: 0
Reputation: 624
SWIFT 5.0 + fetch on background
private func fetchImage(_ photoURL: URL?) {
guard let imageURL = photoURL else { return }
DispatchQueue.global(qos: .userInitiated).async {
do{
let imageData: Data = try Data(contentsOf: imageURL)
DispatchQueue.main.async {
let image = UIImage(data: imageData)
self.userImageView.image = image
self.userImageView.sizeToFit()
self.tableView.reloadData()
}
}catch{
print("Unable to load data: \(error)")
}
}
}
Upvotes: 0
Reputation: 1486
To download Asynchronous image with Kingfisher library you can follow this step,url :https://github.com/onevcat/Kingfisher:
func imageFromUrl(_ urlString: String) {
if let url = URL(string: urlString) {
ImageDownloader.default.downloadImage(with: url, options: [], progressBlock: nil) {
(image, error, url, data) in
DispatchQueue.main.async {
self.imageView.image = image
}
}
}
}
You can also download image with default URLSession.shared.dataTask
func imageFromUrl(_ urlString: String) {
if let url = URL(string: urlString) {
let request = URLRequest(url: url)
URLSession.shared.dataTask(with: request) {(data,response,error) in
if let imageData = data as Data? {
if let img = UIImage(data: imageData){
DispatchQueue.main.async {
self.imageView.image = img
}
}
}
}
}
}
Upvotes: 1
Reputation: 20786
IN SWIFT 3.0
The main thread must be always remain free so it serves the user interface and user interactions.
class ViewController: UIViewController {
@IBOutlet weak var imageView: UIImageView!
private func fetchImage() {
let imageURL = URL(string: "https://i.sstatic.net/9z6nS.png")
var image: UIImage?
if let url = imageURL {
//All network operations has to run on different thread(not on main thread).
DispatchQueue.global(qos: .userInitiated).async {
let imageData = NSData(contentsOf: url)
//All UI operations has to run on main thread.
DispatchQueue.main.async {
if imageData != nil {
image = UIImage(data: imageData as! Data)
self.imageView.image = image
self.imageView.sizeToFit()
} else {
image = nil
}
}
}
}
}
override func viewDidLoad() {
super.viewDidLoad()
fetchImage()
}
}
Upvotes: 8
Reputation: 10124
Just use the size property of UIImage, for example:
NSURL *url = [NSURL URLWithString:path];
NSData *data = [NSData dataWithContentsOfURL:url];
UIImage *img = [[UIImage alloc] initWithData:data];
CGSize size = img.size;
Upvotes: 119
Reputation: 6484
In swift regarding using optionals:
var url:NSURL? = NSURL(string: imageString)
var data:NSData? = NSData(contentsOfURL : url!)
var image = UIImage(data : data!)
Upvotes: 9
Reputation: 105193
In swift:
var url = NSURL.URLWithString("http://www.example.com/picture.png")
var data = NSData(contentsOfURL : url)
var image = UIImage(data : data)
image.size // if you need it
Upvotes: 14