Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How to work with Automatic Reference Counting (ARC)?

In Swift, we mostly use many references of classes like ,

  1. UITableView
  2. UIStepper
  3. UILabel
  4. NSTimer
  5. UISlider and etc..

one example:

var slider : UISlider!

My question is whether we have to create all these as weak refernces by prefixing it as weak, so that ARC will not have a strong hold on it so ARC can delete it as when needed or just creating a strong reference and make it to nil at the viewDidUnload deligate ??

example :

slider = nil

To the point I actually don't know how to manually use ARC or manually handling ARC is not at all needed ?? I have no idea about this meamory handling

Pls do share if u ever came across this and found a solution...

Thanks in advance....

like image 366
Legolas Avatar asked Dec 30 '25 22:12

Legolas


1 Answers

ARC (Automatic Reference Counting) in Swift is explained pretty well in the official documentation.

Below you can find a very simple recap of 4 important aspects of ARC.

1. Basics

ARC associates to each instance of a Class a retainCount integer. This value represents the number of strong references to that specific instance. When this number becomes 0 then the memory used by the instance is freed.

class Something {}
var aVariable = Something()
// now the reference counting for this particular instance of Something is 1

Now our instance of Something is keept in memory since its retainCount value is 1.

var anotherVariable = aVariable 

Now we have 2 strong references to our instance of Something. Good! Its retainCount now is 2 and the instance is still kept in memory!

aVariable = nil

The retainCount has just become 1. No problem, the instance is still in memory.

anotherVariable = nil

Finally the retainCount of our instance has become 0. This means that the instance has been freed and can no longer be accessed.

2. Should you set to nil your variables when you're done with them?

Nope. Infact when a variable goes out of scope ARC automatically decrease the retainCount of the referenced instance.

In the following example, before the last } the retainCount of the instance of Something gets decreased and reach value 0 (and is freed).

func doSomethingUseful() {
    let something = Something()
    // ... do very important stuff here
}

So in a common scenario you don't need to set variables to nil in order to force ARC to free the referenced instance.

Another example:

class Son {}

class Father {
    var sons: [Son]
    init (sons: [Son]) {
        self.sons = sons
    }
}

func lifeGoesOn() {
    let son = Son()
    // here the referenceCout of the instance of Son is 1
    let father = Father(sons: [son])
    // here the referenceCount of the instance of Son is 2...

    // now variable son goes out of scope so the reatinCount of the instance of Son becomes 1
    // also father goes out of scope, so the variable father.sons goes out of scope as well, so the `retainCount` of the instance of Son becomes 0
    // and so both the instances of Father and Son gets freed
}

You can see this like a domino effect. When an instance is freed, all its references to other instances are removed. So the retainCounts of the referenced instances gets decreased. And if becomes 0 they are released. And so on...

3. Retain cycles

Ok, what happen if I have 2 classes as follow?

class Son {
    let father:Father
    init(father:Father) {
        self.father = father
    }
}

class Father {
    var sons: [Son]
    init (sons: [Son]) {
        self.sons = sons
    }
}

Lets create now a reference from a father to its son and viceversa from the son to its father.

func lifeGoesOn() {
    var father = Father(sons:[])
    // retainCount of the instance of Father is 1
    var son = Son(father: father)
    // retainCount of the instance of Father is 2
    // retainCount of the instance of Son is 1
    father.sons.append(son)
    // retainCount of the instance of Father is 2
    // retainCount of the instance of Son is 2

    // Now we have a problem
}

At the of the function the father variable goes out of scope so the retainCount of the instance of Father becomes 1. Similarly the variable son goes out of scope and the retainCount of the instance of Son becomes 1.

The problem here is that the instance of Son references the instance of Father (keeping this instance in alive memory). And the instance of Father references the instane of Son. These 2 instances should not be in memory anymore. They are not accessible by the programmer since all the variable to reference them are gone.

This is a problem.

4. Weak references

When you structure your code you should pay attention to strong retain cycles. Let's how to refactor our code to fix this.

class Son {
    weak var father:Father?
    init(father:Father) {
        self.father = father
    }
}

Now the reference from a Son to its Father is weak. This means it does not count when ARC calculates the number of (strong) references to an instance. And this fix the problem seen in the previous paragraph.

I hope the subject is a little bit more clear now. There are several scenarios I did not cover. Again, the official documentation is pretty good and exhaustive.

Update (to better answer the comment below)

If you have a custom UIViewController (lets call it MyCustomViewController) and this class has a strong property to an object let's see what happen.

class MyCustomViewController : UIViewController {
    var something = Something()
}

class Something {
    init() { // called when memory is allocated
        debugPrintln("The instance of Something has been created")
    }
    deinit { // called when memory is freed
        debugPrintln("The instance of Something has been freed")
    }
}

When you present a MyCustomViewController, an instance of MyCustomViewController is created. Then an instance of Something is created as well.

Now the instance of MyCustomViewController is referenced by the UINavigationController so has retaintCount = 1. Similarly the instance of Something is referenced by the instance of MyCustomViewController so it has retainCount = 1.

So the instance of UINavigationController keeps alive the instance of MyCustomViewController. And the instance of MyCustomViewController keeps alive the instance of Something.

UINavigationController -(strong)-> MyCustomViewController -(strong)-> Something

Next you decide to dismiss MyCustomViewController, so iOS animates it to leave the screen. When it is no longer visible it is removed the reference from the instance of UINavigationController to the instance MyCustomViewController.

UINavigationController -(REMOVED)- MyCustomViewController -(strong)-> Something

This means that the retainCount of the instance of MyCustomViewController becomes 0 because: no one is referencing it now!

So the instance of MyCustomViewController is going to be removed from memory. In this process its properties are nulled.

UINavigationController -(REMOVED)- [free memory] -(REMOVED)- Something

Now the retainCount of the instance of Something has become 0. So it will be removed from memory as well.

UINavigationController -(REMOVED)- [free memory] -(REMOVED)-> [free memory]

Finally, I overidden the init and deinit methods of Something so you can keep track of the allocation and deallocation of a related instance. Looking at the log (or using a breakpoint) you can verify what I said here.

Hope this helps.

like image 141
Luca Angeletti Avatar answered Jan 01 '26 14:01

Luca Angeletti



Donate For Us

If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!