Automatic Reference Counting
Swift uses Automatic Reference Counting (ARC) to track and manage your app's memory usage. In most cases, this means that memory management "just works" in Swift, and you don't need to think about memory management yourself. ARC automatically frees up the memory used by class instances when those instances are no longer needed.
How ARC Works
Every time you create a new instance of a class, ARC allocates a chunk of memory to store information about that instance.
Strong, Weak and Unowned
The purpose of a strong reference is to keep an object alive. Strong referencing might result in several non-trivial problems.
Reference Cycles
Reference cycles for objects occur when properties reference each other.
I collect information from the web from reliable and experienced sources in order to understand the topic myself. After each chapter there is a link to the source
How ARC Works
Every time you create a new instance of a class, ARC allocates a chunk of memory to store information about that instance. This memory holds information about the type of the instance, together with the values of any stored properties associated with that instance.

Additionally, when an instance is no longer needed, ARC frees up the memory used by that instance so that the memory can be used for other purposes instead. This ensures that class instances don't take up space in memory when they're no longer needed.

However, if ARC were to deallocate an instance that was still in use, it would no longer be possible to access that instance's properties, or call that instance's methods. Indeed, if you tried to access the instance, your app would most likely crash.

To make sure that instances don't disappear while they're still needed, ARC tracks how many properties, constants, and variables are currently referring to each class instance. ARC will not deallocate an instance as long as at least one active reference to that instance still exists.

To make this possible, whenever you assign a class instance to a property, constant, or variable, that property, constant, or variable makes a strong reference to the instance. The reference is called a "strong" reference because it keeps a firm hold on that instance, and doesn't allow it to be deallocated for as long as that strong reference remains.
class Person {

    let name: String

    init(name: String) { = name
        print("\(name) is being initialized")

    deinit {
        print("\(name) is being deinitialized")

var reference1: Person?
var reference2: Person?
var reference3: Person?

reference1 = Person(name: "John Appleseed")
// Prints "John Appleseed is being initialized"

reference2 = reference1
reference3 = reference1

reference1 = nil
reference2 = nil
reference3 = nil
// Prints "John Appleseed is being deinitialized"
Defining Memory Management

At hardware level, memory is just a long list of bytes. We treat it as if it were organized into three virtual parts:

  • Stack, where all local variables go.
  • Global data, where static variables, constants and type metadata go.
  • Heap, where all dynamically allocated objects go. Basically, everything that has a lifetime is stored here.

We'll continue saying 'objects' and 'dynamically allocated objects' interchangeably. These are Swift reference types and some special cases of value types.

Memory management is the process of controlling program's memory. It is critical to understand how it works, otherwise you are likely to run across random crashes and subtle bugs.
    Defining Automatic Reference Counting

    Memory management is tightly connected with the concept of Ownership. Ownership is the responsibility of some piece of code to eventually cause an object to be destroyed [1].

    Automatic reference counting (ARC) is Swift ownership system, which implicitly imposes a set of conventions for managing and transferring ownership.

    The name by which an object can be pointed is called a reference. Swift references have two levels of strength: strong and weak. Additionally, weak references have a flavor, called unowned.
      The essence of Swift memory management is
      Swift preserves an object if it is strongly referenced and deallocates it otherwise. The rest is just an implementation detail
      Understanding Strong, Weak and Unowned

      The purpose of a strong reference is to keep an object alive. Strong referencing might result in several non-trivial problems [2]:

      • Retain cycles. Considering that Swift language is not cycle-collecting, a reference R to an object which holds a strong reference to the object R (possibly indirectly), results in a reference cycle. We must write lots of boilerplate code to explicitly break the cycle.
      • It is not always possible to make strong references valid immediately on object construction, e.g. with delegates.

      Weak references address the problem of back references. An object can be destroyed if there are weak references pointing to it. A weak reference returns nil, when an object it points to is no longer alive. This is called zeroing.

      Unowned references are different flavor of weak, designed for tight validity invariants. Unowned references are non-zeroing. When trying to read a non-existent object by an unowned reference, a program will crash with assertion error. They are useful to track down and fix consistency bugs.

      Our further discussion of Swift memory management is bound to be at a lower level of abstraction. We will dive into how ARC is implemented on the compiler level and which steps every Swift object undergoes before being destroyed.
        Defining Swift Runtime

        The mechanism of ARC is implemented in a library called Swift Runtime. It implements such core features as the runtime type system, including dynamic casting, generics, and protocol conformance registration [3].

        Swift Runtime represents every dynamically allocated object with HeapObject struct. It contains all the pieces of data which make up an object in Swift: reference counts and type metadata.

        Internally every Swift object has three reference counts: one for each kind of reference. At the SIL generation phase, swiftc compiler inserts calls to the methods swift_retain() and swift_release(), wherever it's appropriate. This is done by intercepting initialization and destruction of HeapObjects.

          Introducing Side Tables
          Side tables are mechanism for implementing Swift weak references.

          Typically objects don't have any weak references, hence it is wasteful to reserve space for weak reference count in every object. This information is stored externally in side tables, so that it can be allocated only when it's really needed.

          Instead of directly pointing to an object, weak reference points to the side table, which in its turn points to the object. This solves two problems: saves memory for weak reference count, until an object really needs it; allows to safely zero out weak reference, since it does not directly point to an object, and no longer a subject to race conditions.

          Side table is just a reference count + a pointer to an object. They are declared in Swift Runtime as follows (C++ code) [5]:
          class HeapObjectSideTableEntry {
            std::atomic<HeapObject*> object;
            SideTableRefCounts refCounts;
            // Operations to increment and decrement reference counts
          Swift Object Life Cycle

          Swift objects have their own life cycle, represented by a finite state machine on the figure below. Square brackets indicate a condition that triggers transition from state to state [6].
            In live state an object is alive. Its reference counts are initialized to 1 strong, 1 unowned and 1 weak (side table starts at +1). Strong and unowned reference access work normally. Once there is a weak reference to the object, the side table is created. The weak reference points to the side table instead of the object.

            From the live state, the object moves into the deiniting state once strong reference count reaches zero. The deiniting state means that deinit() is in progress. At this point strong ref operations have no effect. Weak reference reads return nil, if there is an associated side table (otherwise there are no weak refs). Unowned reads trigger assertion failure. New unowned references can still be stored. From this state, the object can take two routes:

            • A shortcut in case there no weak, unowned references and the side table. The object transitions to the dead state and is removed from memory immediately.
            • Otherwise, the object moves to deinited state

            In the deinited state deinit() has been completed and the object has outstanding unowned references (at least the initial +1). Strong and weak stores and reads cannot happen at this point. Unowned stores also cannot happen. Unowned reads trigger assertion error. The object can take two routes from here:

            • In case there are no weak references, the object can be deallocated immediately. It transitions into the dead state.
            • Otherwise, there is still a side table to be removed and the object moves into the freed state.
            In the freed state the object is fully deallocated, but its side table is still alive. During this phase the weak reference count reaches zero and the side table is destroyed. The object transitions into its final state.

            In the dead state there is nothing left from the object, except for the pointer to it. The pointer to the HeapObject is freed from the Heap, leaving no traces of the object in memory.
              Reference Count Invariants

              During their life cycle, the objects maintain following invariants:

              • When the strong reference count becomes zero, the object is deinited. Unowned reference reads raise assertion errors, weak reference reads become nil.
              • The unowned reference count adds +1 to the strong one, which is decremented after object's deinit completes.
              • The weak reference count adds +1 to the unowned reference count. It is decremented after the object is freed from memory.

                Automatic reference counting is no magic and the better we understand how it works internally, the less our code is prone to memory management errors. Here are the key points to remember:

                • Weak references point to side a table. Unowned and strong references point to an object.
                • Automatic referencing count is implemented on the compiler level. The swiftc compiler inserts calls to release and retain wherever appropriate.
                • Swift objects are not destroyed immediately. Instead, they undergo 5 phases in their life cycle: live -> deiniting -> deinited -> freed -> dead.

                  Weak References
                  To break strong reference cycles, you can specify the relationship between reference counted objects as weak.

                  Unless otherwise specified, all references are strong and impact reference counts. Weak references, however, don't increase the reference count of an object.

                  In other words, weak references don't participate in the lifecycle management of an object. Additionally, weak references are always declared as optional types. This means when the reference count goes to zero, the reference can automatically be set to nil.
                  weak var owner: User?
                  /// This breaks the User to Phone reference cycle by making the owner reference weak.
                  In the image above, the dashed arrow represents a weak reference. Notice how the reference count of object1 is 1 because variable1 refers to it. The reference count of object2 is 2, because both variable2 and object1 refer to it.

                  While object2 references object1, it does so weakly, meaning it doesn't affect the strong reference count of object1.

                  When both variable1 and variable2 go away, object1 will have a reference count of zero and deinit will run. This removes the strong reference to object2, which subsequently deinitializes.
                    Unowned References

                    There is another reference modifier you can use that doesn't increase the reference count: unowned.

                    What's the difference between unowned and weak? A weak reference is always optional and automatically becomes nil when the referenced object goes away.

                    That's why you must define weak properties as optional var types for your code to compile: The property needs to change.

                    Unowned references, by contrast, are never optional types. If you try to access an unowned property that refers to a deinitialized object, you'll trigger a runtime error comparable to force unwrapping a nil optional type.
                      Capture Lists
                      Swift has a simple, elegant way to break strong reference cycles in closures. You declare a capture list in which you define the relationships between the closure and the objects it captures.

                      To illustrate how the capture list works, consider the following code:
                      var x = 5
                      var y = 5
                      let someClosure = { [x] in
                        print("\(x), \(y)")
                      x = 6
                      y = 6
                      someClosure()        // Prints 5, 6
                      print("\(x), \(y)")  // Prints 6, 6
                      x is in the closure capture list, so you copy x at the definition point of the closure. It's captured by value.

                      y is not in the capture list, and is instead captured by reference. This means that y will be whatever it is when the closure runs, rather than what it was at the point of capture.

                      Capture lists come in handy for defining a weak or unowned relationship between objects used in a closure. In this case, unowned is a good fit, since the closure cannot exist if the instance of a class has gone away.
                        Reference Cycles With Closures
                        Reference cycles for objects occur when properties reference each other. Like objects, closures are also reference types and can cause cycles. Closures capture, or close over, the objects they operate on.

                        For example, if you assign a closure to a property of a class, and that closure uses instance properties of that same class, you have a reference cycle. In other words, the object holds a reference to the closure via a stored property. The closure holds a reference to the object via the captured value of self.
                        class Subscription {
                            var countryCode: String = ""
                            var number: String = ""
                            lazy var completePhoneNumber: () -> String = {
                                self.countryCode + " " + self.number // We capture self; It's a problem
                            deinit {
                        func scope() {
                            var subscription: Subscription? = Subscription()
                            subscription = nil /// Deinit not call
                        Resolve Closures Cycles
                        It is easy
                        lazy var completePhoneNumberWithScope: () -> String = { [weak self] in // GC
                              guard let self = self else {
                                return "No phone available."
                              return self.countryCode + " " + self.number
                        Where Is That Leak?

                        While the app is still running, move over to the bottom of Xcode and click the Debug Memory Graph button:
                          Observe the Runtime Issues in the Debug navigator. They are marked by purple squares with white exclamation marks inside, such as the one selected in this screenshot:
                            In the navigator, select one of the problematic Contact objects. The cycle is clearly visible: The Contact and Number objects keep each other alive by referencing one another.
                              class Number {
                                unowned var contact: Contact
                                // Other code...
                              class Contact {
                                var number: Number?
                                // Other code...
                              Cycles With Value Types and Reference Types
                              Swift types are reference types, like classes, or value types, like structures or enumerations. You copy a value type when you pass it, whereas reference types share a single copy of the information they reference.

                              This means that you can't have cycles with value types. Everything with value types is a copy, not a reference, meaning that they can't create cyclical relationships. You need at least two references to make a cycle.

                              struct Node { // Error A struct value type cannot be recursive or use an instance of itself. Otherwise, a struct of this type would have an infinite size.
                                var payload = 0
                                var next: Node?
                              class Node { // Change from `Struct` to `Class`
                                var payload = 0
                                var next: Node?
                              Reference and Value
                              This is an example of a mixture of value types and reference types that form a reference cycle.

                              Ernie and Bert stay alive by keeping a reference to each other in their friends array, although the array itself is a value type.

                              Make the friends array unowned and Xcode will show an error: unowned only applies to class types.

                              To break the cycle here, you'll have to create a generic wrapper object and use it to add instances to the array. If you don't know what generics are or how to use them, check out the Introduction to Generics tutorial on this site.

                              Add the following above the definition of the Person class:
                              class Person {
                                var name: String
                                var friends: [Person] = []
                                init(name: String) {
                         = name
                                  print("New person instance: \(name)")
                                deinit {
                                  print("Person instance \(name) is being deallocated")
                              do {
                                let ernie = Person(name: "Ernie")
                                let bert = Person(name: "Bert")
                                ernie.friends.append(bert) // Not deallocated
                                bert.friends.append(ernie) // Not deallocated
                              Build and run. Notice that neither Bert nor Ernie is deallocated.
                                The friends array isn't a collection of Person objects anymore, but instead a collection of Unowned objects that serve as wrappers for the Person instances.

                                Build and run. Ernie and Bert now deallocate happily!
                                class Unowned<T: AnyObject> {
                                  unowned var value: T
                                  init (_ value: T) {
                                    self.value = value
                                // Person
                                var friends: [Unowned<Person>] = []
                                do {
                                  let ernie = Person(name: "Ernie")
                                  let bert = Person(name: "Bert")
                                Foundation's NSAutoreleasePool type, later abstracted to the @autoreleasepool block, is a very old concept in iOS development. During the Obj-C era of iOS, usage of this type was important to prevent your app's memory from blowing up in specific cases. As ARC and Swift came around and evolved, very few people still have to manually play around with memory, making seeing it become a rare occurrence.

                                In the pre-ARC Obj-C days of manual memory management, retain() and release() had to be used to control the memory flow of an iOS app. As iOS's memory management works based on the retain count of an object, users could use these methods to signal how many times an object is being referenced so it can be safely dealloced if this value ever reaches zero.

                                Instead of instantly reducing the retain count of an object, autorelease() adds the object to a pool of objects that need to be released sometime in the future, but not now. By default, the pool will release these objects at the end of the run loop of the thread being executed, which is more than enough time to cover all usages of getCoolLabel() without causing memory leaks. Great, right?

                                Because autorelease defers the release of these objects, they will only be released after the run loop ends -- which is way after the execution of emojifyAllFiles. If the contents of these files are large, this would cause serious issues if not crash the app entirely.

                                   func manyPictures() {
                                        autoreleasepool {
                                            for _ in 0 ..< 500_000_000 {
                                                let image = UIImage(named: "penis")
                                    func manyPictures() {
                                        for _ in 0 ..< 500_000_000 {
                                            let image = UIImage(named: "penis")
                                Visual difference in memory usage
                                No Autoreleasepool