В чем разница между lazy stored property и computed property в Swift?

Ответ

Оба типа свойств не хранят значение изначально, но механизм и цель их работы различны.

Аспект Lazy Stored Property (lazy var) Computed Property (var { })
Назначение Отложенная инициализация для оптимизации (тяжелые вычисления или зависимости). Предоставление значения «на лету» на основе других свойств.
Хранение Является stored property. Вычисляет значение один раз при первом обращении и сохраняет его. Не хранит значение. Вычисляет значение каждый раз при обращении.
Синтаксис Использует замыкание для вычисления начального значения: lazy var name = { ... }() Использует getter (и опционально setter): var name: Type { get { ... } set { ... } }
Тип (let/var) Только var (значение устанавливается после инициализации). Может быть var (с get/set) или let (только get, read-only).
Зависимости Может обращаться к self и другим свойствам экземпляра, так как вычисляется позже. Getter может использовать другие свойства. Setter часто изменяет другие stored properties.

Пример lazy property:

class DataLoader {
    lazy var cachedData: [String] = {
        print("Performing expensive loading...")
        return loadDataFromDisk() // Выполнится только один раз
    }()
}
let loader = DataLoader()
print(loader.cachedData) // "Performing expensive loading..." затем данные
print(loader.cachedData) // Данные возвращаются мгновенно (значение сохранено)

Пример computed property:

struct Rectangle {
    var width: Double
    var height: Double

    var area: Double { // Вычисляется каждый раз
        return width * height
    }

    var description: String { // Read-only computed property
        return "Rectangle (width)x(height)"
    }
}
var rect = Rectangle(width: 5, height: 10)
print(rect.area) // 50.0
rect.width = 10
print(rect.area) // 100.0 — вычислено заново

Вывод: Используйте lazy для дорогих или не всегда нужных вычислений, computed — для значений, производных от текущего состояния объекта.

Ответ 18+ 🔞

Давай разберёмся, в чём тут, блядь, разница, а то народ путается, как слепой кот в сортире. Оба этих свойства — и ленивое, и вычисляемое — нихуя не хранят изначально, но цели у них, сука, как небо и земля.

Смотри, вот тебе разбор полётов, чтобы не быть мудаком:

Критерий Ленивое свойство (lazy var) Вычисляемое свойство (var { })
Зачем нужно Отложить тяжёлую инициализацию. Чтобы не грузить систему, пока не приспичило. Дать значение «здесь и сейчас», высранное из других свойств.
Хранит ли? Да, хранит, сука! Считает один раз, при первом запросе, и кладёт в закрома. Больше не парится. Нихуя не хранит! Каждый раз, когда ты к нему лезешь, оно заново всё вычисляет.
Как выглядит Через замыкание: lazy var name = { ... }() Через геттер (и сеттер, если хочешь): var name: Type { get { ... } }
Константа или переменная? Только var, потому что значение проставляется позже инита. Может быть и var (с геттером/сеттером), и let (только для чтения).
Может трогать self? Может, ёпта! Вычисляется позже, когда объект уже готов. Геттер, конечно, может лапать другие свойства. Сеттер — обычно меняет какие-то stored-поля.

Вот тебе пример ленивой сволочи:

class DataLoader {
    lazy var cachedData: [String] = {
        print("Performing expensive loading...")
        return loadDataFromDisk() // Выполнится только один раз
    }()
}
let loader = DataLoader()
print(loader.cachedData) // "Performing expensive loading..." затем данные
print(loader.cachedData) // Данные возвращаются мгновенно (значение сохранено)

Видишь? Первый раз оно похерилось, загрузило данные с диска. Второй раз — уже просто отдало из кэша, не дергаясь. Оптимизация, блядь!

А вот вычисляемое, чтоб ты понимал:

struct Rectangle {
    var width: Double
    var height: Double

    var area: Double { // Вычисляется каждый раз, блядь!
        return width * height
    }

    var description: String { // Только для чтения, вычисляемое
        return "Rectangle (width)x(height)"
    }
}
var rect = Rectangle(width: 5, height: 10)
print(rect.area) // 50.0
rect.width = 10
print(rect.area) // 100.0 — вычислено заново, ёпта!

Тут площадь — она каждый раз, сука, пересчитывается. Ширину поменял — и всё, по новой. Никакого сохранения, чистая математика на коленке.

Итог, ёпта: lazy юзай, когда операция дорогая или не факт, что понадобится. computed — когда значение всегда должно быть свежим и зависит от других полей. Не путай, а то получишь пиздец, а не оптимизацию.