views:

76

answers:

1

When using an Objective-C object that returns asynchronously with a completion handler, like AVAssetExportSession, is there anything wronmg with code like this:

AVAssetExportSession* exportSession = [[AVAssetExportSession alloc] initWithAsset: composition presetName: AVAssetExportPresetHighestQuality];
[exportSession exportAsynchronouslyWithCompletionHandler: ^(void) {
    // export completed
    NSLog(@"Export Complete %d %@", exportSession.status, exportSession.error);
    [exportSession release];
    }];

Instruments reports exportSession as a leak. I've also got a few classes of my own that use the same methodology and they also get reported as leaks.

From everything I've read it seems like the code should follow the proper memory management rules but something must be up. I found a link to this article, but I don't think I'm causing Cyclic Retention.

+3  A: 

Blocks in Objective-C automatically take ownership of objects in their scope, and you do cause a cyclic reference. Your block retains exportSession implicitly, and exportSession likely retains your block.

Memory management rules says you should relinquish ownership of objects as soon as you can. Therefore, the right place to do it, in your case, is after the call to exportAsynchronouslyWithCompletionHandler:.

AVAssetExportSession* exportSession = [[AVAssetExportSession alloc] initWithAsset: composition presetName: AVAssetExportPresetHighestQuality];
[exportSession exportAsynchronouslyWithCompletionHandler: ^(void) {
    // export completed
    NSLog(@"Export Complete %d %@", exportSession.status, exportSession.error);
}];
[exportSession release];

The cyclic reference should be obvious that way: exportSession will be kept alive by the block, and the block itself will be kept alive by the object.

When you deal with blocks, I suggest you use the garbage collected environment.

zneak
The issue is that this is iPhone programming, as such no GC. Make export session a `__block` variable. This will cause it to not retain export session, thus removing the cycle. It shouldn't cause any problems because exportSession itself has to call the handler, thus it is guaranteed to still be alive at that time.
Joshua Weinberg
Thanks guys, using __block on the object (AVAssetExportSession in the example) and releasing it inside the block, as in the question, seems to work. (And if the block isn't retaining the object I would think I would have to wait till the block is done to release the object.)
James Veenstra
@James Veenstra If this solved your problem, consider checking the "accept" mark besides the question score.
zneak