How Swift ARC works?

Swift Automatic Reference Counting
Swift Automatic Reference Counting

Automatic garbage collection in Swift aka ARC works pretty differently than Obj-C

Swift ARC uses Automatic Reference Counting (ARC) to handle memory management. It increases reference count when an instance is owned by another instance, and automatically frees up the memory when there is no owner left. No explicit code required. 

A well-written program uses as little memory as possible. In olden days of iOS when there was Manual Reference Counting, we used to deal with retain count. Retain count of an object increases as and when it’s number of owner increases.

ARC also works in the same way, when object is owned by another object it’s retain count increases by 1. Only thing ARC does extra is that when no one is owning an object it will automatically gets relinquished. Whereas in Manual Reference Counting we had to explicitly call release [obj release]

Lifecycle methods of an instance:

— init: init method allocates chunk of memory for the instance.

deinit: deinit method gets called when the instance is about to release memory it is been holding. Swift have deinit method just like Objective-C had dealloc

In ARC environment there is no direct method to get retain count, we are suppose to follow the best practices and not worry too much about how compiler handles memory management internally. In Non-ARC environment retainCount() method provides the retain count, but who usage Non-ARC anyway.

Apple says ARC “just works” in swift, which is almost true but comes with one small condition “just one” and that is :

  Avoid strong reference cycle! 

So, what is Strong Reference Cycle? Here is an Example:

deinit methods never got called in both the classes because of strong reference cycle.

StrongCycle holds strong reference of VeryStrongCycle, in turn VeryStrongCycle holds strong reference of StrongCycle. This situation is called strong reference cycle. Trust me my intention was not to make it a tongue twister 😉

So how do we break this Strong Reference Cycle?

Another way of breaking the bad errr… reference cycle is by using weak protocol.

Don’t freak out by looking at AnyObject alongside CompanyProtocol, it is another safety measure by Swift.

Apple says that marking the protocol as class-only indicates that the delegate is intended to be used for a class and it must be used as a weak reference inside a class. You mark a protocol as being class-only by inheriting from AnyObject or Class Refer AppleDocs 

In the above code snippet both the deinit() got called and memory released, by declaring Protocols weak we broke the reference cycle.

All references are strong references by default unless otherwise specified.

Okay, so we have broken the shackle of strong reference cycle between classes. Next is closure, we have got problem there too.

Closures are like classes, they are also reference types. Instance variables are accessed within closure by referring self like self.name , self.price and methods are accessed like self.totalCartValue() In either case, these accesses cause the closure to “capture” self, creating a strong reference cycle. Because self holding strong reference of closure and closure is holding strong reference of self Have a look on the following example:

The deint() method never got called in both the classes, because of strong reference cycle with self. Next we will see how to break this cycle by making unowned and weak

Here unowned and weak broke the reference cycle and both the deinit()methods got called. Here weak cartProtocol = self.cartProtocol was not required though, because it was already declared weak and self was unowned. Still to demonstrate the concept I have added the line. Protocols should be declared weak when instance variable of it is not declared as weak.

Weak and unowned references enable one instance in a reference cycle to refer to the other instance without keeping a strong hold on it.

Tip: Sometimes instance variables of typeUIImage or Data, holds a big chunk of memory. We don’t really bother to free up memory even when the instance is not in use. Assigning nil to such instances indicate ARC that we are done with the object for now, please free up the space. This eventually bring down memory footprint. Of-course the variable has to be optional for you to set nil.

At this point we have two keywords unowned and weak doing almost similar job, breaking the reference cycle, then why two keywords? Both actually does the same job but they differ in terms of object’s lifetime.

unowned: Should be used when the lifetime of both the objects are almost same. Also unowned objects can never be nil, thus the instance can’t be declared as optional. Eg. Bank-Money

weak: Should be used when the lifetime of one of the object is smaller. Weak instances can be nil thus they can be declared optional. Eg. Human-iPhone

Before we end this topic Apple have one more thing to say:

Apple Says: Reference counting applies only to reference types (class, closures) and not value types (structenum).

Do you want to know why? Hop on to my next article on Reference Counting & Memory Allocation with Stack and Heap.

1 Comment

Comments are closed