14. Когда value type оказывается в куче, а не на стеке?

Дополнительные вопросы

1. Влияет ли размер value type на то, где его разместят?

Темы

Ответ

1. Свойство класса

Если тип значения хранится в свойстве класса, он лежит внутри экземпляра этого класса. Экземпляр размещается в куче, поэтому и значение оказывается там же.

// Value Type struct Point { var x = 1 } // Reference Type class Holder { // Структура живет в куче var point = Point() }

2. Замыкание

Если замыкание захватывает тип значения и это замыкание вызывают после выхода из функции, значение уже нельзя держать на стеке. Swift сохраняет его в куче, и замыкание продолжает работать с ним.

// Value Type struct Progress { let step = 1 } // Reference Type var getNextStepClosure: ((Int) -> Int)! func initProgress() { let progress = Progress() getNextStepClosure = { value in // Замыкание извне захватывает структуру и держит её в куче. return value + progress.step } } initProgress() // Функция завершилась // Замыкание и Progress продолжают жить print(getNextStepClosure(1)) // 2 print(getNextStepClosure(2)) // 3

3. Тип протокола

Если тип значения кладут в переменную типа протокола, Swift упаковывает его в экзистенциальный контейнер.

Экзистенциальный контейнер это некая упаковка для протокола. Компилятор не знает конкретный тип, который будет подписан под этот протокол, а значит, и не знает его размер. Поэтому для любого значения резервируется одинаковый объём памяти.

Если значению хватает зарезервированного места, оно лежит прямо в контейнере. Если не влезает, то компилятор размещает само значение в куче, а в контейнер кладёт ссылку на него.

protocol Shape {} struct Polygon: Shape { var a = 1 var b = 2 var c = 3 var d = 4 } // Polygon не влезает в контейнер, поэтому само значение лежит в куче let shape: any Shape = Polygon()

Дополнительные вопросы

1. Размер влияет на размещение, когда тип значения хранят как протокол. Если значение не влезает в экзистенциальный контейнер, само значение оказывается в куче. Обычную структуру в переменной компилятор на кучу из-за размера не переносит: она остаётся на стеке.