How to download image asynchronously using blocks?

10,027

Solution 1

You are setting the imageView before the image is done downloading, you need to move the logic into the block. Also there is no reason for you to do an extra dispatch_sync inside of your dispatch_async.

- (IBAction)getImage
{

    dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0),
     ^{
        NSURL *imageURL = [NSURL URLWithString:@"http://example.com/1.jpg"];
        NSData *imageData = [NSData dataWithContentsOfURL:imageURL];

        //This is your completion handler
        dispatch_sync(dispatch_get_main_queue(), ^{
             //If self.image is atomic (not declared with nonatomic)
             // you could have set it directly above
             self.image = [UIImage imageWithData:imageData];

             //This needs to be set here now that the image is downloaded
             // and you are back on the main thread
             self.imageView.image = self.image;

         });
     });

     //Any code placed outside of the block will likely
     // be executed before the block finishes.
}

Solution 2

Check out https://github.com/rs/SDWebImage

I use it to download images in the background with progress notification. It can be added simply to your project using Cocoapods (http://cocoapods.org).

There are several other async image loaders available on Cocoapods and GitHub if that doesn't work for you.

Share:
10,027
Dvole
Author by

Dvole

Updated on June 18, 2022

Comments

  • Dvole
    Dvole almost 2 years

    I want to click a button to start downloading image and to update my UIImageView to new image once it is updated. The problem with my code is that it only downloads stuff, and not updates. It only updates if I click it again. I want it to update the image some time in future, when the image is downloaded. How do I do that?

    Edit: I have found the wrong code, changing it a bit helped and it all works. Here comes another question - how do I simplify this code without turning it a mess? It looks excessive.

    - (IBAction)getImage
    {
    
        dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0),
         ^{
            NSURL *imageURL = [NSURL URLWithString:@"http://example.com/1.jpg"];
            __block NSData *imageData;
    
             dispatch_sync(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0),
                ^{
                    imageData = [NSData dataWithContentsOfURL:imageURL];
    
    
                    dispatch_sync(dispatch_get_main_queue(), ^{
                                                 self.image = [UIImage imageWithData:imageData];
                                             });
                                         });
    
    
         });
    
        self.imageView.image = self.image;
    }
    
  • Vikas Ojha
    Vikas Ojha almost 10 years
    Hi , I am working on the same code.I need to know how can you access the self inside this block as the properties could only be accessed inside the block in the form of getter /setter. using self.imageView.image here should give you an error. Please let me know how you have created a property for this imageView.? Please see my code. stackoverflow.com/questions/23890573/…