2

I have a iOS project in which I am using ARC in my own classes, but have ARC turned off in other libraries like ASIHTTPRequest.

I'm getting huge memory leaks using the code below to fetch an image from a web server:

-(void)buildPhotoView {

self.photoLibView.hidden = NO;

NSString *assetPathStr = [self.cellData objectForKey:@"AssetThumbPath"];

// get the thumbnail image of the ocPHOTOALBUM from the server and populate the UIImageViews
NSURL *imageURL = [NSURL URLWithString:assetPathStr];

__block ASIHTTPRequest *request = [ASIHTTPRequest requestWithURL:imageURL];
__unsafe_unretained ASIHTTPRequest *weakRequest = request;
[weakRequest setCompletionBlock:^{

    // put image into imageView when request complete
    NSData *responseData = [weakRequest responseData];
    UIImage *photoAlbumImage = [[UIImage alloc] initWithData:responseData];
    self.photo1ImageView.image = photoAlbumImage;
}];
[weakRequest setFailedBlock:^{
    NSError *error = [request error];
    NSLog(@"error geting file: %@", error);
}];
[weakRequest startAsynchronous];

}

I've modified the sample code from the ASIHTTPRequest example code page to eliminate compiler warnings in Xcode.

How can I get rid of these memory leaks? I only seem to get them when using blocks.

atxe
  • 5,029
  • 2
  • 36
  • 50
Alpinista
  • 3,751
  • 5
  • 35
  • 46
  • Does instantiating `photoAlbumImage` with an autoreleased object reduce the size of the leak? i.e. `photoAlbumImage = [UIImage imageWithData:responseData];` – FluffulousChimp Oct 12 '11 at 06:01
  • You can't use autoRelease when using Automatic Reference Counting. I don't get memory leaks when I use ASIHTTPRequest WITHOUT using blocks, but i this case I need to because I am doing multiple requests for images, each of which goes into a different UIImageView in the tableCell. With blocks I can include a completion block in the request that puts the image into the correct UIImageView when the request is complete. – Alpinista Oct 13 '11 at 03:28

1 Answers1

7

You're referencing the wrong request variable from inside the completion block. You should reference request in the block (that's why you declare it with the __block identifier). In fact, you shouldn't need to declare weakRequest at all.

If you want the request to be kept in memory, store it in an @property (retain) in your class (the one with the buildPhotoView method perhaps).

  • I declared weakRequest because Xcode displayed a warning: Automatic Reference Counting Issue: Capturing 'request' strongly in this block is likely to lead to a retain cycle. I get the same number of errors when I DON'T declare weakRequest. – Alpinista Oct 13 '11 at 03:20
  • 2
    Oh. In that case, prefix `request` with `__unsafe_unretained` as well as `__block`. –  Oct 13 '11 at 03:27
  • FWIW i tried using: `__block __unsafe_unretained ASIHTTPRequest *request` - which did work in debug mode, but I had crashes in production! - The problem is, that when enabling objective c optimizations this code crashes once you try to access `request`, so DO NOT use both `__unsafe_unretained __block` if it is the sole reference to the request object! :) – Herbert Poul Jan 12 '17 at 13:08
  • You really should not be using `ASIHTTPRequest` anymore. It is long deprecated and not supported by anyone, not even the original developer. –  Jan 19 '17 at 01:50