В Swift, когда тип-значение (value type) не хранится в стеке (stack)?

«В Swift, когда тип-значение (value type) не хранится в стеке (stack)?» — вопрос из категории Swift Core, который задают на 10% собеседований IOS Разработчик. Ниже — развёрнутый ответ с разбором ключевых моментов.

Ответ

Тип-значение (структура или перечисление) по умолчанию хранится в стеке, но попадает в кучу (heap) в следующих сценариях:

  1. Когда он является свойством класса: Все содержимое экземпляра класса размещается в куче.

    class MyClass {
        var myStruct: MyStruct // MyStruct хранится в куче как часть MyClass.
    }
  2. При захвате замыканием с продлённым временем жизни: Если замыкание, захватившее структуру, является @escaping или сохраняется, значение переносится в кучу.

  3. При работе с механизмом Copy-on-Write (CoW): Большие типы-значения (как Array, String, Dictionary) используют кучу для хранения своих буферов. При копировании копируется только ссылка на буфер, а реальное копирование данных в новую область кучи происходит лишь при изменении (write).

    var array1 = [1, 2, 3] // Буфер массива в куче.
    var array2 = array1     // Копируется только ссылка (CoW). Память в куче общая.
    array2.append(4)        // Теперь происходит реальное копирование буфера в новое место кучи.
  4. При использовании indirect для перечислений: Ключевое слово indirect заставляет хранить связанное значение перечисления в куче, позволяя рекурсивные структуры.

    indirect enum LinkedListNode {
        case value(Int, next: LinkedListNode)
        case end
    }