1

I'm working on a Objective-C project and we have ARC enabled. I'm currently dealing with two separate classes, let's call them A and B.

A has a strong reference to B and B has a block property with the copy attribute.

@interface A {
    B *b;
    ...
}
@end

@interface B {
    ...
}
@property (copy) void (^myBlock)();
@end

Now, if inside a method owned by A I try to assign to myBlock:

b.myBlock = ^{ [self doSomething] };

The compiler (correctly) complains:

Capturing 'self' strongly in this block is likely to lead to a retain cycle.

I understand this behaviour and how to work around it, based on the answers to this question. (Basically, a cycle is formed because once the block is copied it will contain a strong reference to A, which has a strong reference to B, which in turn has a strong reference to the block itself.)

Now, if instead of directly assigning the block to the property I pass it to a method of B:

[b takeMyBlock:^{ [self doSomething] }];

And inside that method I do the assignment, the compiler will no longer complain.

My question is: Will that create a memory leak? If so, how to avoid it? Is it possible to annotate the method argument somehow so that the compiler knows the argument is going to be copied?

Thanks in advance.

Community
  • 1
  • 1
Marco Aurélio
  • 2,463
  • 1
  • 21
  • 21

2 Answers2

1

I just encountered the same issue myself. While the issue didn't manifest itself as a leak per se, I actually found the problem while analysing heap growth using the Allocations tool in Instruments -- so it obviously does cause a memory issue.

I think the compiler would have to be pretty smart to pick up on the problem and issue a warning, so my guess is that one of two approaches is needed:

  1. Documentation: As you suggested in your question, clearly document that this method will copy the block passed to it. This might involve naming the block parameter something like blockToCopy (Xcode helpfully displays the block parameter name when using autocompletion). Also, comment the method declaration. If you're using a documentation tool like appledoc this is particularly nice, as your documentation will also appear in Xcode's quick help dialog when option clicking your code.

  2. Never capture self strongly in a block: This is perhaps best practise, as I don't think it's ever a good idea to keep a strong reference to self inside a block. If you have to reference self, use a weak reference. This will certainly avoid the situation you describe. (N.B. referencing an instance variable will also keep a strong reference to self).

Stuart
  • 36,683
  • 19
  • 101
  • 139
0

In ARC, what it does is if a local variable or a WEAK variable loses it reference. The memory will be dealloced immediately since its reference count is zero. However, if you are reallocating a STRONG variable, it will definitely cause a memory leak for strong variable retains even if reference count decays to zero. In this case, you shall set this variable to NIL before reallocation or set the variable to weak if strong property is unnecessary.

donkey
  • 4,285
  • 7
  • 42
  • 68