darksky
darksky

Reputation: 21019

Asynchronous Download of iPad Images

So I have an app that downloads and parses a JSON feed with some URLs. Each request downloads only 4 URLs. Each URL is an image URL and I am trying to display each four. A next button will display the next four while keeping the previous ones visible.

When I run my app, sometimes it works, and sometimes it doesn't. I get an EXEC_BAD_ACCESS error. Furthermore, I believe that this is not the best/most efficient way to download images (even thougH I am doing it asynchronously).

Here is how I am doing it. I would greatly appreciate any design advice/suggestions on how I should change my app to download the images more efficiently.

In my ViewController, I have the following method:

- (void)imageSearchController:(id)searchController gotResults:(NSArray *)results {

    AsyncUIImage *imageDownload;

    for (int i = 0; i < [results count]; i++) {

        imageDownload = [[AsyncUIImage alloc] init];

        // Grab the image data in a dictionary
        NSDictionary *dictionary = [NSDictionary dictionaryWithDictionary:[results objectAtIndex:i]];        
        // Grab the values in an array
        NSArray *values = [NSArray arrayWithArray:[dictionary allValues]];
        // Get the image's URL in a string - strings at index 3
        NSString *url = [NSString stringWithString:[values objectAtIndex:3]];

        imageDownload.delegate = self;
        [imageDownload downloadImageFromURL:url];
        [imageDownload release];
    }
}

This method is the method that gets invoked as soon as the JSON feed has been downloaded (using NSURLConnection - this is the delegate method). It creates an AsyncUIImage object and then passes the URLs of each image to that object to download and display.

My AsyncUIImage class is an object which handles downloading of images. It has the following methods:

First, a method to start the download as follows:

- (void)downloadImageFromURL:(NSString *)url {


    NSURLRequest *theRequest=[NSURLRequest requestWithURL:[NSURL URLWithString:url]
                                              cachePolicy:NSURLRequestUseProtocolCachePolicy
                                          timeoutInterval:60.0];

    // create the connection with the request
    // and start loading the data
    NSURLConnection *theConnection=[[NSURLConnection alloc] initWithRequest:theRequest delegate:self];

    if (theConnection) {
        // Create the NSMutableData to hold the received data.
        // receivedData is an instance variable declared elsewhere.
        data = [[NSMutableData data] retain];
    } 

    else {
        NSLog(@"error in connection");
        [theConnection release];
    }
}

And then the usual NSURLConnection delegate methods. The connectionDidFinishLoading: method is as follows:

- (void)connectionDidFinishLoading:(NSURLConnection *)theConnection {    
    self.image = [UIImage imageWithData:data];
    [self.delegate imageDidLoad:self.image];
}

This method informs the delegate method that an image has been downloaded. So back to the ViewController, that imageDidLoad delegate method will display the images as follows:

- (void)imageDidLoad:(UIImage *)image {

    UIImageView *imageView = [[UIImageView alloc] initWithFrame:CGRectMake(xOffset, yOffset, 192, 192)];
    imageView.image = image;
    [imageView release];

    [self.view addSubview:imageView];
    xOffset = xOffset + 192;

    if (count != 0 && count % 4 == 0) {
        yOffset = yOffset + 192;
        xOffset = 0;
    }

    count++;
}

I do not have extensive experience with asynchronous downloads on the iOS platform, however from programming experiences & iOS experience, I believe that what I am doing has some major flaws.

Does anyone have any ideas/suggestions? Any feedback is highly appreciated.

Thank you.

Upvotes: 0

Views: 540

Answers (2)

Paul N
Paul N

Reputation: 1931

Maybe is not the answer you're looking for, but I have used this library for that purpose: HJCache I made a twitter client app and my own implementation for downloading asynchronous images was causing me a lot of problems too.

After changed to this library everything worked smooth, also you can modify it if you want to add extra features or whatever.

It also let you cache your images and it has no problem with multiple images on a tableview to be downloaded at the same time.

Upvotes: 1

rob mayoff
rob mayoff

Reputation: 385600

    UIImageView *imageView = [[UIImageView alloc] initWithFrame:CGRectMake(xOffset, yOffset, 192, 192)];
    imageView.image = image;
    [imageView release];

    [self.view addSubview:imageView];

By the time you pass imageView to addSubview:, it has been deallocated. You need to release it after you add it as a subview of self.view.

If you google objective-c memory management, you will find many beginner guides to help you understand retain and release.

Upvotes: 1

Related Questions