Ответ
Структуры в Swift по умолчанию хранятся на стеке. Однако есть сценарии, когда их необходимо разместить в куче: для продления времени жизни, передачи по ссылке или совместимости с C API. Почему это может понадобиться: Для создания изменяемого shared state или при работе с низкоуровневыми API.
1. Использование класса-обёртки (Boxing) — безопасный и идиоматичный способ
struct Point { var x, y: Int }
// Класс-обёртка хранит значение в куче
final class Box<T> {
var value: T
init(_ value: T) { self.value = value }
}
// Создаём структуру в куче
let pointInHeap = Box(Point(x: 10, y: 20))
// Меняем значение (оригинальная структура изменяется)
pointInHeap.value.x = 30
print(pointInHeap.value) // Point(x: 30, y: 20)
// Несколько ссылок на одну область памяти
let anotherReference = pointInHeap
anotherReference.value.y = 40
print(pointInHeap.value.y) // 40 (изменение видно через первую ссылку)
Этот подход управляется ARC и безопасен.
2. Прямое ручное управление памятью (Unsafe-операции) — для экспертов
struct Pixel { var r, g, b, a: UInt8 }
// 1. Выделяем память в куче под одну структуру Pixel
let heapPointer = UnsafeMutablePointer<Pixel>.allocate(capacity: 1)
// 2. Инициализируем память значением
heapPointer.initialize(to: Pixel(r: 255, g: 0, b: 0, a: 255))
// 3. Используем память
heapPointer.pointee.g = 128 // Изменяем значение через указатель
print(heapPointer.pointee) // Pixel(r: 255, g: 128, b: 0, a: 255)
// 4. КРИТИЧЕСКИ ВАЖНО: Освобождаем в обратном порядке
heapPointer.deinitialize(count: 1) // Деинициализируем (вызываем деинициализаторы)
heapPointer.deallocate() // Освобождаем память
⚠️ Предупреждение: Unsafe API не управляется ARC. Пропуск deinitialize/deallocate ведёт к утечке памяти, а доступ после освобождения — к сбою. Используйте только при крайней необходимости (взаимодействие с C) и оборачивайте в defer.
Итог: Для большинства задач используйте класс-обёртку (Box). Прямые Unsafe операции оставьте для системного программирования.