56

I'm trying to get an image from an URL and it doesn't seem to be working for me. Can someone point me in the right direction?

Here is my code:

NSURL *url = [NSURL URLWithString:@"http://myurl/mypic.jpg"];

NSString *newIMAGE = [[NSString alloc] initWithContentsOfURL:url
                                       encoding:NSUTF8StringEncoding error:nil];

cell.image = [UIImage imageNamed:newIMAGE];

When I debug the newIMAGE string is nil so something isn't working there.

sth
  • 222,467
  • 53
  • 283
  • 367
TheGambler
  • 3,711
  • 5
  • 38
  • 54

5 Answers5

175

What you want is to get the image data, then initialize a UIImage using that data:

NSData * imageData = [[NSData alloc] initWithContentsOfURL: [NSURL URLWithString: @"http://myurl/mypic.jpg"]];
cell.image = [UIImage imageWithData: imageData];
[imageData release];

As requested, here's an asynchronous version:

dispatch_async(dispatch_get_global_queue(0,0), ^{
    NSData * data = [[NSData alloc] initWithContentsOfURL: [NSURL URLWithString: @"http://myurl/mypic.jpg"]];
    if ( data == nil )
        return;
    dispatch_async(dispatch_get_main_queue(), ^{
        // WARNING: is the cell still using the same data by this point??
        cell.image = [UIImage imageWithData: data];
    });
    [data release];
});
Jim Dovey
  • 11,166
  • 2
  • 33
  • 40
  • 1
    this is synchronous , can you please add a code to download it in background , because, it bloques the ui thread – Houcine May 24 '12 at 14:38
  • 2
    A couple of problems: 1. You have a comment about making sure the cell is still visible. You do that with `UITableViewCell *updateCell = [tableView cellForRowAtIndexPath:indexPath];` followed by `if (updateCell) ...` (and obviously, use this `updateCell` rather than the original `cell` for your update of the `imageView`; 2. Make sure, if doing asynchronously, to initialize the `image` property for your `imageView` before you initiate the asynchronous retrieval process; 3. You really should do caching, so it doesn't have to re-retrieve it every time you scroll back to a previously loaded image. – Rob Mar 13 '13 at 06:58
  • Rob posted clear code example for points 1 & 2 above at -> http://stackoverflow.com/questions/16663618/async-image-loading-from-url-inside-a-uitableview-cell-image-changes-to-wrong (thank you Rob) – tmr Jan 30 '15 at 06:01
5

Ok there's a couple of things wrong here:

  1. The conversion from URL (url) to NSString (newImage) is incorrect, what the code actually does there is try to load the contents of "http://myurl/mypic.jpg" into the NSString.

  2. The -imageNamed method takes a string that is a path of a local file, not a URL as an argument.

You need to use an NSData object as an intermediary, like in this example: http://blogs.oreilly.com/digitalmedia/2008/02/creating-an-uiimage-from-a-url.html

Justicle
  • 14,761
  • 17
  • 70
  • 94
4

the accepted answer asynchronous version worked very slow in my code. an approach using NSOperation worked light years faster. the code provided by Joe Masilotti --> objective - C : Loading image from URL? (and pasted below):

-(void) someMethod {
    // set placeholder image
    UIImage* memberPhoto = [UIImage imageNamed:@"place_holder_image.png"];

    // retrieve image for cell in using NSOperation
    NSURL *url = [NSURL URLWithString:group.photo_link[indexPath.row]];
    [self loadImage:url];
}

- (void)loadImage:(NSURL *)imageURL
{
    NSOperationQueue *queue = [NSOperationQueue new];
    NSInvocationOperation *operation = [[NSInvocationOperation alloc]
                                        initWithTarget:self
                                        selector:@selector(requestRemoteImage:)
                                        object:imageURL];
    [queue addOperation:operation];
}

- (void)requestRemoteImage:(NSURL *)imageURL
{
    NSData *imageData = [[NSData alloc] initWithContentsOfURL:imageURL];
    UIImage *image = [[UIImage alloc] initWithData:imageData];

    [self performSelectorOnMainThread:@selector(placeImageInUI:) withObject:image waitUntilDone:YES];
}

- (void)placeImageInUI:(UIImage *)image
{
    [self.memberPhotoImage setImage:image];
}
Community
  • 1
  • 1
tmr
  • 1,500
  • 15
  • 22
1

In Swift 3 and 4

let theURL = URL(string:"https://exampleURL.com")
let imagedData = NSData(contentsOf: theURL!)!
let theImage = UIImage(data: imagedData as Data)
cell.theImageView.image = theImage

This will be done in the main thread.

And to perform the same in asynchronous/background thread

   DispatchQueue.main.async(){
      let theURL = URL(string:"https://exampleURL.com")
      let imagedData = NSData(contentsOf: theURL!)!
      let theImage = UIImage(data: imagedData as Data)
   }
   cell.theImageView.image = theImage
Naishta
  • 11,885
  • 4
  • 72
  • 54
1

Updating upon Jim dovey answer,[data release] is no longer required because in the updated apple guidelines. Memory management is done automatically by ARC (Automatic counting reference) ,

Here is the updated asynchronous call,

dispatch_async(dispatch_get_global_queue(0,0), ^{
        NSData * data = [[NSData alloc] initWithContentsOfURL: [NSURL URLWithString: @"your_URL"]];
        if ( data == nil )
            return;
        dispatch_async(dispatch_get_main_queue(), ^{
            self.your_UIimage.image = [UIImage imageWithData: data];
        });

    });
Frostmourne
  • 156
  • 1
  • 19