1
votes

A question about the retain cycle with block. In the ARC Model.

Say, an instance of view controller named 'vc', it holds reference to a block. Within the block, vc is used for some action :

{

    //this is a piece of code snippet in vc
    self.vcBlock = {

        [self someAction];

    }

}

I understand that this leads to retain cycle , because vc holds a strong reference to the block while the block will hold a strong reference to vc as well.

But how about referencing a member variable of vc whithin the block:

{

    //this is a piece of code snippet in vc
    self.vcBlock = {

        [self.obj someAction];

    }

}

Does this cause retain cycle? I think that the relationship of these references can be expained as below:

enter image description here

So, I think there is no retain cycle exists, any problem?

4

4 Answers

3
votes

The expression self.obj is evaluated at runtime, which requires the block to maintain the value of self, so you still have a cycle.

However, if your diagram is the relationship you want, that is that your block has a reference to the object which was referenced by self.obj at the time the block is created then you can simply achieve this by using a temporary local variable. I.e. code along the lines of:

SomeType objRef = self.obj;
self.vcBlock = ^{ ... [objRef someAction]; ... };

This avoids the cycle as the value (an object reference) returned by self.obj is first copied into the local objRef, and then that value becomes part of the block's saved values (aka its environmemt).

This is a common approach in this kind of situation, but remember if the value of self.obj changes before the block is executed then that change will not be seen by the block - which seems to be what you wish from your diagram.

Also note that a cycle per se is not a problem, you can create cycles and later break them without issue - indeed it is not uncommon. A cycle is only a problem if it results in unreclaimed resources (like memory).

HTH

3
votes

Property access is translated to method calls at compile time, so in your second example, it's still self that is retained, and you have exactly the same loop.

1
votes

It does exist retain cycle, vcBlock holds a strong reference to self(the vc), or you can take it as

[[self obj] someAction];

if we call this method in another form like this (if the obj is a ivar)

[_obj someAction];//in fact ,it's equivalent to [self->obj someAction]

so the block always holds a strong reference to self.

1
votes

In the second case, you can avoid the retain cycle:

{
    MyObject* obj = self.obj;
    self.vcBlock = ^{ [obj someAction]; };
}