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.
MAZeroingWeakRefhas 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.