Here is a quick introduction, along with the full articles list

Automatic Reference Counting (ARC) is a compile-time mechanism that takes over memory management. This mechanism works only for objects that are stored on the heap (reference types)

Before ARC appeared, developers had to manage memory and objects lifetime manually. For these purposes, they used the following functions: retain, release, and autorelease

retain is an instance method that makes reference count of the instance + 1

release is an instance method that makes reference count of the instance — 1. When the count reaches 0, it calls the instance method dealloc to dispose of the instance and free up memory on the heap

autorelease is an instance method that adds the instance to an autorelease pool for having a deferred release call

Today, when code is being compiled, ARC inserts retain, release, and autorelease calls to the code automatically. And, roughly speaking, that is all that ARC does. However, it is smart enough to make it okay, avoiding unnecessary insertions. The code remains quite efficient. So, there is no need to think about manual reference management anymore

The critical point here is that ARC is namely a compile-time mechanism. So, it doesn’t manage memory at runtime or do some magic with the heap there

class Person {
public let name: String

Autorelease Pool

An autorelease pool is an instance of NSAutoreleasePool

It is a mechanism for having deferred release behavior. A pool itself is placed on the stack. It contains the objects, which were added by autorelease method calls. When a pool is being released (removed from the stack), it calls the release method of each item inside (sends a release message to all of them)

Each function has its pool. When a function is called, a pool is created and put onto the top of the stack. Each object created inside the function, which got an autorelease message, is added to the pool. When the function ends, the pool is being released

However, if another pool is manually created inside the function, the objects will be added there because now that pool is placed onto the top of the stack. So, objects are added into the last created pool

In general, there is no need to create pools manually. E.g., UIKit and AppKit create a pool automatically when a touch event starts and release it when the event ends (run loop iteration)

However, it can be useful to create a pool manually to prevent big memory surges in cycles. E.g., heavy objects that are created on each cycle iteration should be released at the end of the iteration

// some function body

Let’s imagine that each image takes ~20Mb in memory. So, without autoreleasepool it will take ~200Mb by the end of the function. But now, it takes ~20Mb within the whole function call. Thus, no significant memory surges there

However, it works only for Objective-C objects (NSObject) that got an autorelease message. For objects that come from Swift, it doesn’t work anyway

Strong Reference Cycles Between Class Instances

// Problem

A weak reference is used when the object’s lifetime is shorter than its holder. It can store only optional values. weak tells ARC not to insert retain for the object (not to make one more strong reference)

Note: Property observers aren’t called when ARC sets a weak reference to nil

// Solution (using weak)

An unowned reference is used when the object’s lifetime is the same or longer than its holder. It can store optional and non-optional values. unowned also tells ARC not to insert retain for the object (not to make one more strong reference)

ARC can make it nil, and if you try to get the value, then you will have the runtime error

// Solution (using unowned)

weak and unowned can also be applied to variables

weak var person = Person()
unowned var card = CreditCard()

The difference between unowned and unowned(unsafe) (unowned is safe by default) is that Swift for unowned checks at runtime whether the object is alive. So, in this case, it works like implicit unwrapping (!). And if the object doesn’t exist (it is nil), Swift throws an error when trying to get the object value

But when unowned(unsafe) is used, Swift doesn’t verify that the object is still alive, and it can get access to other data stored in this memory region. Thus, in this case, you can get an undefined state. But using unowned(unsafe) can increase performance

The best practice is to avoid using unowned at all because the code anyway becomes unsafe. The best practice is to use weak always and check explicitly that the object is alive

ARC is not a garbage collector. Unlike standard garbage collectors, where the resources are deallocated when the app needs memory, objects in Swift are deallocated once the last strong reference gets nil (release calls dealloc)

Strong Reference Cycles for Closures

A strong reference cycle can also occur if you assign a closure to a property of a class instance, and the body of the closure captures the instance

// Problem

There is a capture list that defines the rules to capture objects within the closure body

// ... [unowned self, weak delegate = self.delegate, someVariable]
// Solution

Resources

Software Developer