Avoiding retain cycles with blocks

Joel Bernstein:

In the traditional pattern for breaking retain cycles, the object with the strong reference is responsible for notifying the other object when it’s deallocating, so the other object can change its weak pointer to nil. This would neatly avoid the problem, because messages sent to nil don’t cause exceptions. Sadly, there’s no way to tell a block to nil-out a pointer in its code.

It was around this point that I remembered Mike Ash’s magical MAZeroingWeakRef class. MAZeroingWeakRef has a target property that is guaranteed to always either point to a valid object, or nil. Instead of writing:

__block typeof(foo) blockFoo = foo;
foo.myBlock = ^{ [blockFoo doSomething]; };

you can write:

MAZeroingWeakRef* fooRef = [MAZeroingWeakRef refWithTarget:foo];
foo.myBlock = ^{ [fooRef.target doSomething]; };

MAZeroingWeakRef is indeed a great generalized solution to the mismatch between blocks and the lifespan of their originating objects.

But I have to disagree with the hardline stance Joel states in his first conclusion (“Never use __block to break a retain cycle”) — it’s fine to use them so long as you can “cancel” the invocation of the outstanding block in your originating object’s -dealloc method.

blocks Mar 18 2011