I am working through some retain-cycle issues with blocks/ARC, and I am trying to get my head around the nuances. Any guidance is appreciated.
Apple's documentation on "Blocks and Variables" (http://developer.apple.com/library/ios/#documentation/cocoa/Conceptual/Blocks/Articles/bxVariables.html) says the following:
If you use a block within the implementation of a method, the rules for memory management of object instance variables are more subtle:
If you access an instance variable by reference, self is retained; If you access an instance variable by value, the variable is retained. The following examples illustrate the two different situations:
dispatch_async(queue, ^{
// instanceVariable is used by reference, self is retained
doSomethingWithObject(instanceVariable);
});
id localVariable = instanceVariable;
dispatch_async(queue, ^{
// localVariable is used by value, localVariable is retained (not self)
doSomethingWithObject(localVariable);
});
I find this explanation confusing.
- Is this appropriate use of the "by value" / "by reference" terminology? Assuming that these variables are of the same type (id), it seems like the distinguishing characteristic between them is their scope.
I do not see how self is being referenced in the "by reference" example? If an accessor method were being used, (e.g. - below), I could see self being retained.
doSomethingWithObject(self.instanceVariable);
Do you have any guidance on when one might want to do things one way or the other?
- If conventional wisdom is to utilize the "by value" variables, it seems like this is going to result in a lot of additional code for additional variable declarations?
- In a circumstance where nested blocks are coming into play, it seems like it may be more maintainable to avoid declaring the blocks inside of each other as one could ultimately end up with a potpourri of unintentionally retained objects?
Is this appropriate use of the "by value" / "by reference" terminology? It's at least analogous to the typical use. Copying a value to a local variable is like copying a value onto the stack; using an ivar is like passing a pointer to a value that's stored somewhere else.
I do not see how self is being referenced in the "by reference" example? When you use an instance variable inside a method, the reference to
self
is implied. Some people actually writeself->foo
instead offoo
to access an ivar just to remind themselves thatfoo
is an ivar. I don't recommend that, but the point is thatfoo
andself->foo
mean the same thing. If you access an ivar inside a block,self
will be retained in order to ensure that the ivar is preserved for the duration of the block.Do you have any guidance on when one might want to do things one way or the other? It's useful to think in terms of the pass by reference/pass by value distinction here. As AliSoftware explained local variables are preserved when the block is created, just as parameters passed by value are copied when a function is called. An ivar is accessed through self just as a parameter passed by reference is accessed through a pointer, so its value isn't determined until you actually use it.
it seems like this is going to result in a lot of additional code for additional variable declarations? Blocks have been a feature of the language for a while now, and I haven't noticed that this is a problem. More often, you want the opposite behavior: a variable declared locally that you can modify within a block (or several blocks). The
__block
storage type makes that possible.it seems like it may be more maintainable to avoid declaring the blocks inside of each other as one could ultimately end up with a potpourri of unintentionally retained objects? There's nothing wrong with letting one or more blocks retain an object for as long as they need it -- the object will be released just as soon as the blocks that use it terminate. This fits perfectly with the usual Objective-c manual memory management philosophy, where every object worries only about balancing its own retains. A better reason to avoid several layers of nested blocks is that that sort of code may be more difficult to understand than it needs to be.
Think of the case of using
instanceVariable
as an equivalent of writingself->instanceVariable
. An instance variable is by definition "attached" to theself
object and exists while the self object exists.Using
instanceVariable
(orself->instanceVariable
) means that you start from the address of self, and ask for an instance variable (that is offset of some bytes from theself
object original address).Using
localVariable
is a variable on its own, that does not rely on self and is not an address that is relative to another object.As the blocks capture the variables when they are created, you typically prefer using instance variables when you mean "when the block is executed, I want to get the value of the instance variable at the time of the execution" as you will ask the
self
object for the value of the instance variable at that time (exactly the same way as you would call[self someIVarAccessorMethod]
). But then be careful not to create some retain cycles.On the other hand, if you use
localVariable
, the local variable (and notself
) will be captured when the block is created, so even if the local variable changes after the block creation, the old value will be used inside the block.In that example the output will show that
instanceVariable
andself.property
are accessed thru theself
object, so self was retained but the value ofinstanceVariable
andself.property
are queried in the code of the block and they will return their value at the time of execution, respectively"ivar-after"
and"prop-after"
. On the other hand,localVariable
was retained at the time the block was created and its value was const-copied at that time, so the lastNSLog
will show"locvar-before"
.self
is retained when you use instance variables or properties or call methods on self itself in the code of the block. Local variables are retained when you use them directly in the code of the block.Note: I suggest you watch the WWDC'11 and WWDC'12 videos that talks about the subject, they are really instructive.