1

I have problems to obtain image from url on iPad 3 4G test device. Code works with ipad 1 & 2 and also with iphone 3gs and iphone 4. But seems that image is nil when requested from server.

I don't experience the issue, but clients report problems...

I belive that problem is in the following code

Code:

NSData *data = [NSData dataWithContentsOfURL:[NSURL URLWithString:@"http://www.image.com/img_download/499441.jpg"]];
UIImage *thumbnail = [UIImage imageWithData:data];

Url in this code is not real but it is correct for clarification.

Thanks!

Rob
  • 415,655
  • 72
  • 787
  • 1,044
Nikola Jovic
  • 2,329
  • 2
  • 16
  • 17

2 Answers2

1

A couple of thoughts:

  1. I'd suggest using dataWithContentsOfURL:options:error: instead of just dataWithContentsOfURL and reporting the error code is. Or use NSURLConnection or other framework (e.g. AFNetworking?) that might provide greater diagnostic information. But I suspect that dataWithContentsOfURL:options:error: can provide the necessary error information.

  2. Can you place this in context? For example, is this something that your app is doing asynchronously (e.g. thumbnails for a tableview)? If so, are you using NSOperationQueue with a reasonably small maxConcurrentOperationCount rather than a global dispatch queue, to make sure you don't exceed the number of permissible concurrent connections?

    For example, if you're updating your tableview like so:

    dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT,0), ^{
        NSData *data = [NSData dataWithContentsOfURL:[NSURL URLWithString:@"image.com/img_download/499441.jpg"]];
        UIImage *thumbnail = [UIImage imageWithData:data];
    
        // presumably you're updating your UI like so
        dispatch_async(dispatch_get_main_queue(), ^{
            // update UI
        });
    });
    

    you should do the following. First, define a class property:

    @property (nonatomic, strong) NSOperationQueue *queue;
    

    Second, you should initialize this in viewDidLoad, specifying how many concurrent operations are acceptable:

    self.queue = [[NSOperationQueue alloc] init];
    self.queue.maxConcurrentOperationCount = 4;
    

    And finally, replace dispatch_async with:

    [self.queue addOperationWithBlock:^{
        NSError *error = nil;
        NSData *data = [NSData dataWithContentsOfURL:[NSURL URLWithString:@"image.com/img_download/499441.jpg"]
                                             options:0
                                               error:&error];
    
        if (error)
        {
            // log or display what the error is
        }
        else
        {
            UIImage *thumbnail = [UIImage imageWithData:data];
    
            if (thumbnail)
            {
                // update UI in the main queue
    
                [[NSOperationQueue mainQueue] addOperationWithBlock:^{
    
                    // make sure the cell is still visible
    
                    UITableViewCell *updateCell = [tableView cellForRowAtIndexPath:indexPath];
    
                    // if so, update the image
    
                    if (updateCell)
                    {
                        updateCell.imageView.image = thumbnail;
                    }
                }];
            }
        }
    }];
    

    Note, you may also want to do caching to eliminate reloading images that you've already downloaded. See https://stackoverflow.com/a/14444605/1271826 for an example. You could also cache images to Documents folder if you want to cache images across sessions (though some care must be done to determine changes in images).

To my second point, sometimes connection problems are not caused by the particular line that fails, but is a symptom of a broader problem, and as such, we need a little more info about how you're using the code in your question.

Community
  • 1
  • 1
Rob
  • 415,655
  • 72
  • 787
  • 1,044
  • i am using following code: dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT,0), ^{ NSData *data = [NSData dataWithContentsOfURL:[NSURL URLWithString:@"http://www.image.com/img_download/499441.jpg"]]; UIImage *thumbnail = [UIImage imageWithData:data]; – Nikola Jovic Jan 24 '13 at 07:30
  • That's my point exactly. If you using a global queue, it's concurrent, but many servers limit how many concurrent requests they'll accept from a given client. Use `NSOperationQueue`. I'll update my answer with example. – Rob Jan 24 '13 at 07:33
  • please update code for this situation. and use blocks if possible – Nikola Jovic Jan 24 '13 at 07:36
  • Thanks a lot. I will try code soon and say for results. What is max number of possible connections. I more than 4. – Nikola Jovic Jan 24 '13 at 07:47
  • @NikolaJovic Not only do servers not frequently like more than four, but your unlikely to see the downloads much faster if you use a larger `maxConcurrentOperationCount`. And given that you're having problems, a lower number is safer. Note, my suggestion on point #2 is recommended if the users are seeing the first few images, but blank images for subsequent images. If they're not seeing any images, there might be something else going on, in which case, looking at the `code` and `localizedDescription` associated with the `NSError` will be helpful in diagnosing what's going on. – Rob Jan 24 '13 at 08:21
  • Hi. I replace code for this purpose. On simulator works fine but I need to wait my clients to test it. If error is present I display alert view with localized description... Thanks a lot... – Nikola Jovic Jan 24 '13 at 11:03
0

Add Base64 class www.imthi.com/wp-content/uploads/2010/08/base64.zip in your project Now encode as:

NSData* data = UIImageJPEGRepresentation(yourImage, 1.0f);
[Base64 initialize];
NSString *strEncoded = [Base64 encode:data];

Decode as:

[Base64 initialize]; 
NSData* data = [Base64 decode:strEncoded ];;
image.image = [UIImage imageWithData:data];
Krishnan8190
  • 320
  • 2
  • 8