How is memory management handled in iOS?

Memory management is very important in any application, especially in iOS apps that have memory and other constraints. Hence, this is one of the standard questions that is asked in one form or another. It refers to ARC, MRC, reference types, and value types.

Swift uses Automatic Reference Counting (ARC). This is conceptually the same thing in Swift as it is in Objective-C. ARC keeps track of strong references to instances of classes and increases or decreases their reference count accordingly when you assign or unassign instances of classes (reference types) to constants, properties, and variables. It deallocates memory used by objects which reference count got down to zero. ARC does not increase or decrease the reference count of value types because, when assigned, these are copied. By default, if you don’t specify otherwise, all the references will be strong references.

One of the gotchas of ARC that you need to be aware of is Strong Reference Cycles. For a class instance to be fully deallocated under ARC, it needs to be free of all strong references to it. But there is a chance that you could structure your code in such a way that two instances strongly reference each other and therefore never let each other’s reference count drop down to zero. There are two ways of resolving this in Swift: weak references and unowned references. Both of these approaches will assign an instance without keeping a strong ref- erence to it. Use the weak keyword for one and the unowned keyword for the other before a property or variable declaration. Weak reference is used when you know that a reference is allowed to become nil whereas unowned refer- ence is used when you are certain that the reference has a longer lifecycle and will never become nil. Since weak references can have a value or no value at all, they must be defined as optional variables. An unowned reference has to be defined as non-optional since it is assumed to always have a value.

Another important gotcha is Strong Reference Cycle in Closures. When you use closures within a class instance they could potentially capture self. If self, in turn, retains that closure, you’d have a mutual strong reference cycle between closure and class instance. This often occurs when you use lazy loaded properties for example. To avoid it, you’d use the same keywords weak and unowned. When you define your closure, you should attach to its defi- nition a so called capture list. A capture list defines how the closure would handle references captured in it. By default, if you don’t use a capture list, everything will be strongly referenced. Capture lists are defined either on the same line where the closure open bracket is or on the next line after that. They are defined with a pair of square brackets and every element in them has a weak or unowned keyword prefix and is separated from other elements by a comma. The same thinking applies to a closure capture list as to variable references: define a capture variable as a weak Optional if it could become nil’ and the closure won’t be deallocated before then, and define a captured reference as unowned if it will never become nil before the closure is deallocated.