Как в Swift обеспечить хранение объекта на стеке? Приведи пример.

«Как в Swift обеспечить хранение объекта на стеке? Приведи пример.» — вопрос из категории Управление памятью, который задают на 10% собеседований IOS Разработчик. Ниже — развёрнутый ответ с разбором ключевых моментов.

Ответ

В Swift хранение на стеке обеспечивается использованием типов-значений (value types), главным образом структур (struct) и перечислений (enum). При создании экземпляра такой тип размещается в стеке вызовов текущего потока (если не происходит escape в кучу, например, при захвате замыканием).

Пример: структура Point, хранящаяся на стеке.

// 1. Объявляем структуру (тип-значение)
struct Point {
    var x: Int
    var y: Int

    // Метод, работающий с мутабельным self (изменяет копию)
    mutating func moveBy(x deltaX: Int, y deltaY: Int) {
        x += deltaX
        y += deltaY
    }
}

// 2. Создаем экземпляр. Локальная переменная `origin` размещается на стеке.
func createPoint() {
    var origin = Point(x: 0, y: 0) // Выделение памяти на стеке
    print("Initial: ((origin.x), (origin.y))")

    // 3. Присваивание создает новую, независимую копию на стеке.
    var anotherPoint = origin // Копирование значений (copy-on-write для оптимизации)
    anotherPoint.x = 10
    print("Origin: ((origin.x), (origin.y))") // (0, 0) - не изменился
    print("Another: ((anotherPoint.x), (anotherPoint.y))") // (10, 0)

    // 4. Передача в функцию также создает копию (если параметр не `inout`).
    func printPoint(_ p: Point) {
        print("Printed point: ((p.x), (p.y))")
    }
    printPoint(origin)

    // 5. Изменение через mutating метод.
    origin.moveBy(x: 5, y: 3)
    print("Moved origin: ((origin.x), (origin.y))") // (5, 3)
}

createPoint()

Ключевые характеристики типов-значений (стековых):

  • Копирование по значению: При присваивании или передаче в функцию создается новая, независимая копия данных.
  • Отсутствие разделяемого состояния: Изменение одной переменной не влияет на другие.
  • Автоматическое управление памятью: Память в стеке освобождается автоматически при выходе из области видимости (функции, скоупа).
  • Высокая производительность: Выделение и освобождение памяти в стеке — очень быстрые операции (просто сдвиг указателя стека).

Сравнение с типами-ссылками (куча):

Аспект Тип-значение (struct, enum) Тип-ссылка (class)
Хранение Стек (по умолчанию) Куча (динамическая память)
Копирование Создается новая копия Копируется указатель (ссылка)
Управление памятью Автоматическое (стек) ARC (счетчик ссылок)
Наследование Нет (но есть протоколы) Есть (одиночное)
Идентичность Сравнение по значению (==) Сравнение по ссылке (===)

Важно: Компилятор Swift может применять оптимизации (например, copy-on-write для больших структур), чтобы избежать дорогостоящего копирования, пока данные не будут изменены, но семантика поведения остается value-type.