Виды типов

В языке Swift типы делятся на две группы: типы значений и ссылочные.

К типам значений относятся перечисления и структуры (например, стандартные строки, числа, словари и массивы относятся к ним). Переменные с таким типом содержат непосредственно само значение, а переприсвоение между ними происходит через полное копирование этого значения.

import Foundation

var firstValue: Double = 11
var secondValue: Double = firstValue

secondValue += 1

print(firstValue)
// 11

print(secondValue)
// 12

Ссылочными типами являются классы и замыкания (они же блоки). Такие переменные хранят только ссылку на объект, но не его сам, а копирование производится путем создания еще одной ссылки.

import UIKit

var firstView: UIView = UIView()
var secondView: UIView = firstView

print(firstView.tag)
//0

secondView.tag = 10

print(secondView.tag)
// 10

print(firstView.tag)
// 10

К преимуществам значений относятся простота использования и безопасность работы с ними при конкурентном программировании, так как другой поток не сможет изменить ваши данные.

Ссылочные же типы наоборот, могут создать трудности в многопоточных приложениях, но позволяют экономить память, держа в ней лишь небольшое число общих экземпляров. Однако, чтобы при этом не столкнуться с утечкой памяти, нужно понимать механизм ее управления и очистки. В Swift за это отвечает Automatic Reference Counting (ARC), подсчитывающий количество ссылок на каждый объект. И только при снижении этого показателя до нуля объект деинициализируется и удаляется из памяти.

В большинстве случаев ARC прекрасно справляется со своей работой самостоятельно. За исключением зацикливаний, когда один объект имеет ссылку на другой, а тот на него. В этой ситуации разработчику необходимо сделать одну из ссылок «слабой» (не учитываемой ARC), превратив связь в одностороннюю. Для этого служат ключевые слова weak (с необязательными переменными) и unowned (с обязательными).

import Foundation

class ControllerPart {
    var controller: Controller?

    init(controller: Controller) {
        self.controller = controller
    }
}

class Controller {
    var part: ControllerPart?
    
    deinit {
        print("Controller deleted")
    }
}

var controller: Controller? = Controller()
var controllerPart: ControllerPart? = ControllerPart(controller: controller!)

controller!.part = controllerPart!

controller = nil
/* 
  Controller not deleted, because controllerPart still has a reference to it.
  But if we make this reference weak:

    weak var controller: Controller?
    or
    unowned var controller: Controller

  Controller deleted
*/

У замыканий это делается в списке захвата.

import Foundation

class Mechanism {
    var strength = 0
    lazy var action: () -> Void = {
        [unowned self] in
        self.strength++
    }

    deinit {
        print("Mechanism deleted")
    }
}

var mechanism: Mechanism? = Mechanism()

// Make lazy property active
mechanism?.action()

mechanism = nil
// Mechanism deleted

Дополнительные материалы: