21

I have little bit confusion in ARC reference count can you please tell me what will be reference count of bellow code.

var vc1 = UIViewController()
var vc2 = vc1
var vc3 = vc2
weak var vc4 = vc3

Question is what will be the:

  • reference count of vc1 ?
  • reference count of vc2 ?
  • reference count of vc3 ?
  • reference count of vc4 ?
vaibhav
  • 4,038
  • 1
  • 21
  • 51
jignesh Vadadoriya
  • 3,244
  • 3
  • 18
  • 29

4 Answers4

20

Here, vc1, vc2, vc3 refer to the same object. So, the reference count of that object is 3. When vc4 refer to the same object, since it is weak reference, the reference count will not be incremented by 1. So, the reference count after this will also be 3

  1. The reference count of UIViewController object that is created and referred by vc1 after first line of code is 1.

    var vc1:UIViewController? = UIViewController() // strong reference 
    
  2. After vc2 refers to the same object as vc1. The reference count of object turns to 2

    var vc2:UIViewController? = vc1 // strong reference
    
  3. After vc3 refers to the same object as vc1 and vc2. The reference count of object turns to 3

    var vc3:UIViewController? = vc2 // strong reference
    
  4. After vc4 refers to the same object as vc1, vc2 and vc3. Since vc4 is weak reference, the reference count will not be incremented. That means the count is still 3.

    weak var vc4:UIViewController? = vc3 // weak reference
    

What it means:

Execute the following code.

   vc1 = nil; // reference count = 3-1 = 2
   vc2 = nil; // reference count = 2-1 = 1
   vc3 = nil; // reference count = 1-1 = 0 and object is destroyed

Now, print the value of vc4. It will be nil. This happens because the reference count of object turns to zero and all of the variables refers to same object.

Edit:

Using CFGetRetainCount in the below code gives the following results as stated here:

var vc1:NSDate? = NSDate()
print(CFGetRetainCount(vc1)) // 2 - I expected this to be 1 as only one variable is strongly referring this object. 

var vc2:NSDate? = vc1
print(CFGetRetainCount(vc1)) // 3 - reference count incremented by 1 (strong reference)

var vc3:NSDate? = vc2
print(CFGetRetainCount(vc3)) // 4 - reference count incremented by 1 (strong reference)

weak var vc4:NSDate? = vc1
print(CFGetRetainCount(vc1)) // 4 - reference count not incremented (weak reference)

vc1 = nil
print(CFGetRetainCount(vc2)) // 3 - reference count decremented by 1 (strong reference removed)

vc2 = nil
print(CFGetRetainCount(vc3)) // 2 - reference count decremented by 1 (strong reference removed)

vc3 = nil 
print(vc4) // nil - reference count should be decremented by 1 (last strong reference removed)

// Also due to the final line vc3 = nil, reference count should become zero
// However, we can't use `CFGetRetainCount` to get reference count in this case
// This is due to the final strong reference being removed and object getting destroyed

The reason why CFRetainCount is giving 2 in the 1st line has been discussed here. Thanks @CodaFi and @Sahil for your discussion in comments

Community
  • 1
  • 1
KrishnaCA
  • 5,615
  • 1
  • 21
  • 31
  • Thanks KrishnaCA for your amazing response – jignesh Vadadoriya Nov 25 '16 at 07:00
  • 2
    why CFGetRetainCount giving 4 then @KrishnaCA? – Sahil Nov 25 '16 at 07:09
  • @KrishnaCA i have also same question Sahil ask? – jignesh Vadadoriya Nov 25 '16 at 07:10
  • 1
    http://stackoverflow.com/questions/2640568/how-to-get-the-reference-count-of-an-nsobject – Sahil Nov 25 '16 at 07:15
  • 5
    @Sahil CFGetRetainCount returns 4 because @KrishnaCA misunderstands the intent of variable assignment with respect to reference counts. In this example, refcounts are incremented not because of the assignments in and of themselves, but because the first three assignments are to a *strong reference*. The assignment to a weak reference still performs a temporary increment of the reference count (in particular, it invokes `_swift_weakInit`). This is all implementation defined, tho. You shouldn't have to think about it :) – CodaFi Nov 25 '16 at 07:18
  • I never used CFRefCount to count references. But, I do understand strong reference and weak reference. In Swift, I believe that every ref is strong reference unless it is specified as weak. But, `temporary increment of reference count` is something I have not read about. @CodaFi, can you please provide me the source for this – KrishnaCA Nov 25 '16 at 07:21
  • 1 more thing you can assign nil to vc1, vc2, vc3 @KrishnaCA – Sahil Nov 25 '16 at 07:24
  • 1
    @KrishnaCA Sure. Take a look around [HeapObject.cpp](https://github.com/apple/swift/blob/2fe4254cb712fa101a220f95b6ade8f99f43dc74/stdlib/public/runtime/HeapObject.cpp) for the set of calls we can emit for this stuff. The temporary increment is an implementation detail and can be flattened away if the optimizer can guarantee the lifetime of each of these references. – CodaFi Nov 25 '16 at 07:31
  • @Sahil, we can do that if we define them as optionals. Thanks for pointing out – KrishnaCA Nov 25 '16 at 07:32
  • 1
    Even if you (first change the types, then) set them to nil, the semantics of ARC are such that we don't have to honor them with a decrement. That it happens at all is, again, implementation defined! ARC is a whole lotta fun now that we don't have to carry around all the dumb baggage ObjC's calling convention required. – CodaFi Nov 25 '16 at 07:36
  • @CodaFi, @Sahil, I just checked retain count of object after `var vc1:UIViewController = UIViewController()` this using `CFGetRetainCount`. It's giving me 2. Also, temporary increment of reference count is not happening after weak reference is set. – KrishnaCA Nov 25 '16 at 08:16
  • I refer you to [Bill's comments](http://stackoverflow.com/questions/21658714/arc-instance-variable-retain-release#comment32740293_21658714), then. You can't rely on this working consistently, you can only know the compiler will respect the semantics of ARC. – CodaFi Nov 25 '16 at 08:24
  • @KrishnaCA Nice explain +1 :) – Jaywant Khedkar Feb 26 '18 at 12:45
4

You can use CFGetRetainCount function for check ref count.

var vc1 = UIViewController()
var vc2 = vc1
var vc3 = vc2
weak var vc4 = vc3


print(CFGetRetainCount(vc1)) //4
print(CFGetRetainCount(vc2)) //4 
print(CFGetRetainCount(vc3)) //4
print(CFGetRetainCount(vc4)) //4

you can also refer this Get Ref Count

Community
  • 1
  • 1
Sahil
  • 9,096
  • 3
  • 25
  • 29
  • `CFGrtRetainCount` does return 4 but you're not answering what's been asked. Take a look at CodaFi's comments to see why your answer is incorrect – fpg1503 Nov 25 '16 at 07:27
  • @Sahil, try getting retain count for each step here once and check the result. I just tried it. The retain count if `vc1` after `var vc1 = UIViewController()` is 2. Please confirm – KrishnaCA Nov 25 '16 at 08:13
2

In my opinion vc1 to vc3 increases the retain count and the by default property is strong until we specify those as weak.

strong: Strong is generally used by a class to establish ownership of an object. It increases the retain count (something ARC deals with for you), it basically keeps the object that is pointed to in memory until that class instance stops pointing to it. This is usually what you want, but there it can cause something called a “retain cycle.”

In case of vc4 as you dec as weak:

weak: This gives a pointer to an object, but does not claim ownership, and does not increase the retain count. It basically keeps a valid pointer to an object as long as another class points to it strongly. If nothing else is trying to retain it, the weak pointer is automatically set to nil.

vaibhav
  • 4,038
  • 1
  • 21
  • 51
1

1,2,3,4 - reference count will be 3

The only exception when reference count won't be incremented - 4th line, because of weak modificator

Vladyslav Zavalykhatko
  • 15,202
  • 8
  • 65
  • 100