1

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?

itenyh
  • 1,921
  • 2
  • 23
  • 38

4 Answers4

3

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.

Avi
  • 7,469
  • 2
  • 21
  • 22
  • You mean : Obj *obj = [self getObjc]; [obj someAction]; ? – itenyh Nov 09 '15 at 03:39
  • Something like that, though unless you have a `getter=myGetter` attribute in the property declaration, the method will have the same name as the property. The setter will be `setObj`, in your example. – Avi Nov 09 '15 at 03:44
  • Also, be aware that using the instance variable directly (`_obj`) won't help you. That still retains `self`, because `_obj` is a struct member, and ARC won't (can't) retain at the struct level. – Avi Nov 09 '15 at 03:45
3

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

CRD
  • 52,522
  • 5
  • 70
  • 86
1

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.

edisongz
  • 121
  • 1
  • 3
1

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

{
    MyObject* obj = self.obj;
    self.vcBlock = ^{ [obj someAction]; };
}
gnasher729
  • 51,477
  • 5
  • 75
  • 98