Ответ
Нет, не всегда. Хотя семантика ссылочных типов (классов) в Swift предполагает размещение в куче, компилятор проводит агрессивные оптимизации, которые могут изменить это поведение.
Стандартный случай: Куча
По умолчанию экземпляры классов создаются в куче, что позволяет иметь несколько ссылок на один объект и управлять памятью через ARC.
class StandardClass { var value = 10 }
let obj = StandardClass() // Экземпляр, скорее всего, в куче
let ref = obj // Две ссылки на один объект в куче
Оптимизации компилятора (Stack Promotion)
Компилятор Swift (в режиме -O) может переместить объект из кучи в стек, если может доказать безопасность этого:
- Локальная область видимости: Объект создается и не покидает пределы функции.
- Отсутствие escape-анализа: На объект не создается внешних ссылок, которые переживут функцию.
- Размер и простота: Объект не слишком велик и не имеет сложных зависимостей.
func calculate() -> Int {
class LocalCalculator { var a = 5; var b = 3 }
let calculator = LocalCalculator() // Может быть оптимизирован в стек!
return calculator.a + calculator.b
}
// 'calculator' не используется вне функции -> кандидат на оптимизацию.
Ключевые исключения и гарантии
- Явное требование кучи: Если класс передается как
@escapingзамыкание, сохраняется в свойство или возвращается из функции — он гарантированно будет в куче. - Value-типы (struct, enum): Почти всегда размещаются в стеке (или внутри другого объекта), если не обернуты в
Box-класс (например, при использовании с@escaping).
Вывод: Размещение в куче — это семантика, а не строгая гарантия реализации. Компилятор может оптимизировать размещение для повышения производительности, не меняя наблюдаемого поведения программы.