A retain cycle happens when two objects store a strong reference to each other. The simplest case is object a
storing a strong reference to object b
and b
doing the opposite [1]. Retain cycles are a problem in Objective-C because they make ARC believe that these objects are always in use even when these objects are not referenced from anywhere else.
Let's review some examples. You have object z
which allocates a
and b
, makes use of them, and then disposes them. If a
and b
created a retain cycle between themselves in the first place, a
and b
won't be deallocated. If you do that several times you would be seriously leaking memory.
Another real world example of a retain cycle is if a
allocates and strongly references a b
object, but you also store a strong reference from b
to a
(many smaller objects in the object graph may need to access their parents).
The most usual solutions in these cases would be to make sure that contained objects only have weak references to its containing objects, and also make sure that sibling objects don't contain strong references to each other.
Another solution (generally less elegant, but possibly appropriate in some situations) could be having some kind of custom cleanup
method in a
that nils its reference to b
. Thus b
would get deallocated when cleanup
is called (if b
is not strongly referenced elsewhere). This is cumbersome because you cannot do this from a
's dealloc
(it never gets called if there is a retain cycle) and because you have to remember to call cleanup
at appropriate times.
- Note that retain cycles are also transitive (e.g., object
a
strongly references b
which strongly references c
which strongly references a
).
With all this said: memory management of blocks is quite tricky to understand.
Your first example could create a temporary retain cycle (and only if your self
object stores a strong reference to someObject
). This temporary retain cycle goes away when the block finishes execution and is deallocated.
During execution, self
would store a reference to someObject
, someObject
to the block
, and the block
to self
again. But again, it is only temporary because the block is not permanently stored anywhere (unless [someObject successBlock:failure:]
implementation does that, but that is not frequent for completion blocks).
So, the retain cycle is not an issue in your first example.
Generally, retain cycles within blocks are only an issue if some object is storing the block rather than executing it directly. Then it's easy to see that self
strongly references the block
and the block
has a strong reference to self
. Note that accessing any ivar from inside a block automatically generates a strong reference to self
in that block.
The equivalent to making sure that the contained object does not strongly reference its container is using __weak SelfClass *weakSelf = self
for accessing both methods and ivars (the better if you access ivars through accessors, as when using properties). Your block's reference to self
will be weak (it's not a copy, it's a weak reference) and that will allow self
to de deallocated when it's no longer strongly referenced.
It can be argued that it's good practice to always use weakSelf
inside of all blocks, stored or not, just in case. I wonder why Apple didn't make this the default behavior. Doing this generally doesn't do anything harmful to the block code, even if actually unneeded.
__block
is rarely used on variables that point to objects, because Objective-C doesn't enforce immutability of objects like that.
If you have a pointer to the object, you can call its methods, and these methods can modify it, with or without __block
. __block
is more (only?) useful on variables of basic types (int, float, etc.). See here for what happens when you use __block
with an object pointer variable. You can also read more about __block
in Blocks Programming Topics by Apple.
Edit: Fixed mistake regarding __block
usage on object pointers. Thanks to @KevinDiTraglia for pointing it.