Где хранится Value Type в Swift?

Ответ

Место хранения Value Type (структуры, перечисления, кортежи) определяется его контекстом, а не самим типом.

Правила размещения:

  • В стеке: Локальные переменные и параметры функций, не захваченные замыканием.
  • В куче (Heap): Когда value type является:
    1. Свойством ссылочного типа (class).
    2. Захвачен замыканием, которое само хранится в куче.
    3. Упакован (например, при использовании с протоколами Any или AnyObject).

Пример:

struct Point { var x, y: Int }

func stackExample() {
    var p = Point(x: 1, y: 2) // Хранится в стеке.
}

class Container {
    var point = Point(x: 3, y: 4) // Хранится в куче, как часть экземпляра Container.
}

func heapExample() {
    var localPoint = Point(x: 5, y: 6)
    let closure = { print(localPoint.x) } // `localPoint` захватывается и может быть перемещен в кучу.
}

Ключевой вывод: Swift оптимизирует производительность, храня value types в стеке где это возможно, но прозрачно перемещает их в кучу при необходимости.

Ответ 18+ 🔞

А, слушай, вот эта вся хуйня про стек и кучу — она многих вводит в ступор, а на деле всё проще, чем кажется. Смотри, у нас есть value types: структуры, перечисления, кортежи. Так вот, где они живут — в стеке или в куче — зависит не от того, что они за хуйня, а от того, где они используются. Вот в чём, блядь, весь фокус.

Где что лежит, если по-простому:

  • В стеке (быстро, чисто, по делу): Это когда у тебя локальная переменная в функции или параметр, который замыкание не схавало. Создал — поработал — выкинул. Красота.
  • В куче (ну тут уже посложнее): Value type отправляется в эту помойку, когда:
    1. Он — свойство какого-нибудь класса. Ну, типа, класс — он всегда в куче, а значит и всё, что в нём сидит, туда же.
    2. Его захватило замыкание, которое само-то живёт в куче. Захватило — и всё, прощай, стек, теперь ты заложник кучи.
    3. Его насильно упаковали (boxing), например, когда ты пытаешься запихнуть структуру в Any или ещё какую-нибудь универсальную хуйню.

Смотри, как это выглядит в коде, ёпта:

struct Point { var x, y: Int }

func stackExample() {
    var p = Point(x: 1, y: 2) // Всё, пизда, тут он в стеке. Быстро и чётко.
}

class Container {
    var point = Point(x: 3, y: 4) // А вот эта точка — она уже в куче, потому что сидит внутри класса, этого пидораса ссылочного.
}

func heapExample() {
    var localPoint = Point(x: 5, y: 6)
    let closure = { print(localPoint.x) } // Внимание, блядь! `localPoint` захвачен! Теперь он, скорее всего, поедет в кучу вместе с замыканием.
}

Итог, который надо запомнить, чтобы не ебать мозг: Свифт — он не мудак, он старается держать value types в стеке, где это возможно, потому что там быстро. Но если обстоятельства, блядь, вынуждают (типа, класс или замыкание), то он без лишнего шума переносит эту хуйню в кучу. Ты этого даже не заметишь, но производительность может просесть. Вот такая, блядь, магия.