Reputation: 21019
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
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
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