Blocks inside NSMutableArray leaking (ARC)

2019-02-13 23:23发布

问题:

I have some operations that are inside blocks. This operations, only update an UIImage like this:

^(UIImage *image) {
            self.myImage = image;
        }];

My image is calculated by accessing the internet with a NSURLConnection. When I receive the image from the internet, I call that block that is inside a NSMutableArray. So far so good. My issue is that when I have multiple images that have the same URL, instead of making multiple calls, I just add a new block to the NSMutableArray inside the class that handles the connection. This way, I make one single call, and update multiple images that share the URL. Everything works ok, the problem is that I am leaking blocks. I add the block like this to the NSMutableArray:

 if( (self = [super init]) ) 
    {
        self.connectionURL=url;
        self.arrayOfBlocks=[NSMutableArray array];
        [arrayOfBlocks addObject:completion];
    }
    return self;

This is when the connection class is initialized. This is when I need to add a new block to the NSMutableArray (I only add it, and that's it):

[arrayOfBlocks addObject:completion];

This is when I finally receive the call back, and start executing the blocks:

 for (MyBlock blockToExecute in arrayOfBlocks)
    {
        blockToExecute([UIImage imageWithData:data]);
    }

The problem is that this is leaking somehow. I am not able to counteract using releases or auto-releases because I am on ARC environment. So what could be a solution?


回答1:

This is a well-known leak in Apple's frameworks. It isn't caused by your use of blocks.

Here's a previous question about it and a bug report.



回答2:

The block retains 'self', and I'm guessing that 'self' retains the blocks (via the 'arrayOfBlocks' property). If that property is retained, you have a circular reference and a leak. I don't think ARC handles circular references, so you should probably empty the block array after you're done with it (or set the property to nil), and make sure nothing else references the blocks.