views:

52

answers:

1

Inspired by Apple's LazyTables sample, I've just built myself a class called ImageLoader. It's agonizingly clever of me. And as is often the case when I'm agonizingly clever, I'm up against the limits of my wisdom about how to handle the memory of this object.

The thing gets instantiated from a UIViewController subclass inside viewDidLoad, thusly:

ImageDownloader *downloader = [[ImageDownloader alloc] init];
[downloader startDownloadWithImageView:self.theImageView
                           andImageURL:[NSURL URLWithString:myUrlString]];

Inside that method in ImageDownloader, I go:

-(void)startDownloadWithImageView:(UIImageView *)imageView
                      andImageURL:(NSURL *)url
{
 self.theImageView = imageView;
 [UIApplication sharedApplication].networkActivityIndicatorVisible = YES;
 self.activeDownload = [NSMutableData data];

 NSURLConnection *conn = [[NSURLConnection alloc]
  initWithRequest:[NSURLRequest requestWithURL:url] delegate:self];
 self.imageConnection = conn;
 [conn release];
}

and my delegate method as a NSURLConnectionDelegate is (in pertinent part):

- (void)connectionDidFinishLoading:(NSURLConnection *)connection
{  
 UIImage *image = [[UIImage alloc] initWithData:self.activeDownload];
 theImageView.image = image;
 [image release];
}

There's obviously all kinds of error checking it doesn't do yet, but you get the brilliance of it, right? I can now pass this thing a UIImageView and a NSURL and let it lazy-load the image asynchronously. Sa-weet!

So here's the question... How do I release downloader? I don't think I can autorelease from the ViewController where I create it, because I wouldn't expect NSURLConnection to call its delegate by the end of the run loop. Can I release self at the end of connectionDidFinishLoading? I've never seen that done, feels a little weird to release myself inside a method of myself.

My other thought is, I could make this a singleton and just not be concerned about it sticking around until we terminate. But I'd rather have the object come to life and go away cleanly.

Incidentally, the next step of my cleverness will be to add this functionality as a category of UIImageView. It'd be kind of neat to call [imageView asynchronouslyLoadImageFromURL:(NSURL *)url].

+2  A: 

You could always put a [self retain] in the -startDownloadWithImageView:andImageURL: method and a [self release] in the -connectionDidFinishLoading: method. It's unconventional, obviously, but that would allow you to autorelease it after creating it without worrying about it being killed prematurely.

Jeff Kelley
That works, but you're right that it's unconventional. I was hoping there would be a more standard Way These Things are Done. Is what I'm doing here a deviation from usual design patterns?
Dan Ray
I've written similar code, scratched my head and made it a singleton. +1 for the retain/release autorelease : we shouldn't be afraid of using these methods - its what they are there for!
Andiih
One thing to add: I'm not sure how the Cocoa garbage collector will react in this situation if it doesn't think that anything is referring to your object. Definitely test a lot if you enable it.
Jeff Kelley
@Andiih: Fair enough. This is the answer I'm going with. @Jeff Kelley: Seems fine, but I'll do a lot of poking around before I release anything (or even show it to my manager!). Thanks!
Dan Ray
Jeff - this is iPhone - no garbage collection!
Andiih