55

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?

pkamb
  • 33,281
  • 23
  • 160
  • 191
cyclingIsBetter
  • 17,447
  • 50
  • 156
  • 241
  • 2
    Why would that be a problem? Once the image is downloaded you will know its size. You can also make the image view the size you want and stretch the image to fit. – David Rönnqvist Jun 10 '12 at 21:40

9 Answers9

119

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;
fbernardo
  • 10,016
  • 3
  • 33
  • 46
  • Or set the size you want on the image view and just stretch the image once its downloaded to fit the image view. (You should stretch AND keep aspect, everything else looks weird) – David Rönnqvist Jun 10 '12 at 21:42
  • ah ok...but I don't understand how resize this image for my imageView; I sholud to create a miniature and I haven't a lot of space for my imageView (max 236 width and max 60 for height); in this space I should load image from url but it should be proportionate... – cyclingIsBetter Jun 10 '12 at 21:51
  • 2
    I think what you want is to set the contentMode of the UIImageView to UIContentViewScaleAspectFit. But have a look at the documentation. – fbernardo Jun 10 '12 at 22:03
  • Thanks for this code. I have a question, how do I display a "loading" while the image is being retrieved and notify if the picture fails to download? – Shannon Cole Jul 10 '13 at 01:49
  • @Shannon Did you get the answer ? – Arpit B Parekh Aug 03 '15 at 14:47
  • hey man. This line `NSData *data = [NSData dataWithContentsOfURL:url];` It is not very heavy for a cellForRowAtIndexPath? – jose920405 Sep 09 '15 at 14:07
  • not directly relevant to the question or answer, here, for getting size, instead of using last line in the code, CGSize size = img.size; use, int size = data.length; – mavericks Oct 06 '15 at 09:37
  • Is there a better way to get image size with alamofireimage? I want to do this same thing but with async – user805981 Jun 15 '16 at 20:21
14

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
yegor256
  • 102,010
  • 123
  • 446
  • 597
9

In swift regarding using optionals:

var url:NSURL? = NSURL(string: imageString)
var data:NSData? = NSData(contentsOfURL : url!)
var image = UIImage(data : data!)
theDC
  • 6,364
  • 10
  • 56
  • 98
8

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.stack.imgur.com/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()
}

}
Ashok R
  • 19,892
  • 8
  • 68
  • 68
1

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
                       }
                    }
                }
            }
        }
    }
Krishna Kumar Thakur
  • 1,456
  • 12
  • 27
1

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
    }
}
Damian Carrillo
  • 1,218
  • 9
  • 11
Ricardo Barroso
  • 634
  • 9
  • 11
0

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)")
        }
    }
}
Bary Levy
  • 584
  • 5
  • 6
0

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.
}
m02ph3u5
  • 3,022
  • 7
  • 38
  • 51
John Pitts
  • 653
  • 6
  • 17
0

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)
    }
    
}
Ricardo Barroso
  • 634
  • 9
  • 11