Виды типов
В языке 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
Дополнительные материалы: