Reputation: 2785
Let's say I'm trying to access self
from within a block:
[someObject successBlock:^(NSArray *result) {
[self someSuccessMethod];
} failure:^(NSString *errorMessage, int status) {
[self someFailureMethod];
}];
I understand that this creates a retain cycle and that someObject
and self
never get de-alloced.
What's confusing me is what actually happens with/without the __block
keyword. I can fix the retain cycle by making a __weak
reference to self:
__weak MyClass* me = self;
[someObject successBlock:^(NSArray *result) {
[me someSuccessMethod];
} failure:^(NSString *errorMessage, int status) {
[me someFailureMethod];
}];
I don't need to use __block
here, because I'm not trying to modify me
from within the block. From what I understand, if I don't use __block
, a copy of me
is referenced inside the block. My question is: if what's being referenced inside the block is just a copy of the object, why does the original code block create the retain cycle? I would guess that the reference to self
is just a copy, since I'm never using the __block
keyword. Am I thinking about this incorrectly?
Upvotes: 8
Views: 5370
Reputation: 9566
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.
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.
Upvotes: 4
Reputation: 5081
Your first example will not create a never ending retain cycle. There will be retain cycle, all right, but once the blocks are done, the reference form the blocks to the someObject
will be removed. So the someObject
will live at least until the blocks are done. Such temporary retain cycle could be a good or bad thing, depending on what you want:
If you need your someObject
alive at least until its blocks completions, it's okay. However, if there's no reason to keep that object, you should implement it using 'weak' referencing.
Eg. myObject is a view controller which in those blocks fetches a picture from the net. If you pop that someObject
form the navigation controller, the controller won't be able to display the picture after fetching it, so there's no need to keep it. The success or error are irrelevant, user is not anymore interested in the picture someObject
was supposed to fetch. In such case, the usage of weak is better option, however the code in blocks should expect than self
could be nil.
Upvotes: 3
Reputation: 4585
You can path self as block's argument, exactly giving variable name 'self', this will protect from selfretaining in block.
And you are whrong with 'someObject and self never get de-alloced': self will be released when blocks deallocated. Blocks will be deallocated with someObject. SomeObject will be deallocated when it have no more references. So if your self-object owns someObject, just release someObject when you don't need it any more.
Upvotes: 0
Reputation: 540005
In the first case, the block captures self
, i.e. it saves a copy of self
as another strong pointer. That increases the retain count of the pointed-to object, and causes the retain cycle.
In the second case, the block captures me
, i.e. it saves a copy of me
as another weak
pointer. That does not increase the retain count and therefore causes no retain cycles.
(If you print the address of me
outside and inside the block, you will see that
the addresses are different. The block has its own weak pointer to the object.)
If the pointed-to object is deallocated, all weak references (including the one saved by
the block) are set to nil
by the Objective-C runtime.
(I just hope that I got this right.)
Upvotes: 7