5

I'm having a bit of trouble getting my head around referencing self within a block, and not creating a retain cycle.

Can you let me know if my understanding is correct:

If I ever reference self within a block, it will create a retain cycle, and instead I should be creating a weak reference to self outside of the block and then using that weak reference inside the block?

Thanks!

Wise Shepherd
  • 2,228
  • 4
  • 31
  • 43

1 Answers1

11

Yes, that is correct, with a few exceptions:

A retain cycle only happens if self ends up retaining the block indirectly, e.g. setting property myblock on property of self myproperty:

self.myproperty.myblock = ^{ [self dosomething]; }; // ERROR: Retain Cycle

However, a retain cycle doesn't (usually) happen when using blocks for something like dispatch code, like this:

dispatch_async(dispatch_get_main_queue(), ^{ [self dosomething]; }); // Safe, dispatch_async will not be retained by you

Unless of course you call that dispatch_async function inside a block that has the criteria for being a retain cycle.

It is really confusing, and it's something I hope gets fixed. Now, for my own opinion:


It wasn't always the case, in pre-ARC code this wasn't an issue, but since blocks now automatically retain any objects they capture, it's an issue.

I wish this would get fixed, as it'd be a quite easy fix, by having self's type be a __weak instancetype const instead of a instancetype const. It would also solve some issues with creating class clusters in ARC, which admittedly isn't the largest of issues, but it still exists.

As far as advantages to retain cycles, there are not many.

Richard J. Ross III
  • 55,009
  • 24
  • 135
  • 201
  • 1
    A retain cycle is not strictly an error -- it's often possible for the owner of the Block to dispose of that Block before its own destruction, breaking the cycle and avoiding any problem. – jscs Sep 11 '12 at 03:40
  • Is it safe to just create a weak reference to self and always use that weak reference inside the block, just to ensure no retain cycle? (Assuming I'm ok with the possibility that when the block executes, selfWeak can be a nil pointer?) – Wise Shepherd Sep 11 '12 at 15:59
  • @WiseShepherd of course, that's how you fix retain cycles, in most situations. – Richard J. Ross III Sep 11 '12 at 16:07
  • @newacct actually, no. In MRC code, blocks do not retain objects passed in. Check out this paste bin example (it uses `-retainCount`, i know, but it serves the purpose): http://pastebin.com/23L5wwTJ. Either compile with GCC or with `-fno-objc-arc`, and retainCount never changes. – Richard J. Ross III Sep 11 '12 at 18:45
  • 1
    Sorry, I left out a part. *When a block is copied* (which is what happens in the cases in this question, when you dispatch or store a block), it automatically retains any objects it captures in both MRC and ARC. https://developer.apple.com/library/ios/documentation/cocoa/Conceptual/Blocks/Articles/bxVariables.html#//apple_ref/doc/uid/TP40007502-CH6-SW4 – newacct Sep 11 '12 at 20:13
  • @RichardJ.RossIII There's a retain cycle in both examples. The difference is that the retain cycle in the first example is a memory leak--self can't be released because it has an ivar (the block) which retains it. In the second example, the retain cycle exists until the block is executed, after which the block (which has been copied to the heap) releases its reference to `self`. – Christopher Pickslay Sep 12 '12 at 05:17