В каких сценариях следует использовать value types (структуры и перечисления) в Swift?

Ответ

Value types (структуры struct и перечисления enum) следует использовать по умолчанию, особенно для независимых, копируемых данных.

Основные сценарии применения:

  1. Независимые копии: Когда при присваивании или передаче в функцию нужна изолированная копия данных.
    struct Point {
        var x, y: Int
    }
    var origin = Point(x: 0, y: 0)
    var anotherPoint = origin // Создается полная копия
    anotherPoint.x = 10
    print(origin.x) // Осталось 0, исходный экземпляр не изменен
  2. Потокобезопасность: Поскольку каждый поток работает со своей копией, не требуется синхронизация.
  3. Небольшие, простые модели данных: Например, CGPoint, Date, URL.
  4. Семантика значения: Когда идентичность объекта не важна, важны только его свойства (два экземпляра с одинаковыми данными считаются равными).

Преимущества value types:

  • Предсказуемость: Изменения в одной копии не затрагивают другие.
  • Безопасность в многопоточности: Отсутствует гонка данных (data race) при работе с локальными копиями.
  • Оптимизация памяти: Компилятор может использовать технику copy-on-write для эффективной работы с большими структурами (например, Array, String).

Когда не использовать:

  • Для управления разделяемым ресурсом (например, сетевым соединением).
  • Когда требуется наследование (используйте протоколы и композицию).

Ответ 18+ 🔞

Слушай, а вот этот твой вопрос про value types — это ж классика, прям как в том анекдоте про Герасима и Муму! Все вокруг орут: «Используй структуры, блядь, они безопасные!», а ты стоишь такой и думаешь: «Мууу?..» То есть нихуя не понял, зачем эта вся движуха.

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

struct Point {
    var x, y: Int
}
var origin = Point(x: 0, y: 0)

И отдал её другу: var anotherPoint = origin. Друг её взял, и это уже ЕГО копия, сука! Он там своё x на 10 поменял, а у тебя в origin всё ещё ноль, красота! Никаких «ой, а я думал, мы одной точкой пользуемся». Это и есть та самая предсказуемость, о которой все так заливаются.

А теперь главный пиздец, из-за которого все их и любят — потокобезопасность. Представь, у тебя десять потоков, и каждый долбит по своей копии структуры. Они же не делят одну общую память, у каждого своя изолированная песочница! Никаких гонок (data race), никаких сюрпризов, когда из одного потока неожиданно прилетает пиздюлина в данные. Спокойствие, только спокойствие, как говорил тот ещё тип.

Используй их для всего простого и самодостаточного: координаты, даты, URL — вся эта мелочёвка. Если два экземпляра с одинаковыми полями для тебя неотличимы — это семантика значения, твоё. Бери структуру и не парься.

Ну и оптимизация, ёпта! Компилятор — хитрая жопа. Он видит, что ты создал массив на миллион элементов, и не будет тупо копировать все эти данные при каждом чихе. Используется copy-on-write: пока ты не начал менять свою копию, вы все смотрите на одни и те же данные. Как только полез что-то редактировать — тут-то тебе и выдают твою личную, отдельную копию. Гениально и эффективно.

А когда нихуя не использовать-то?

Вот смотри. У тебя есть, условно, менеджер сетевых запросов, который один на всё приложение. Это же разделяемый ресурс, состояние которого должно быть одно на всех! Если ты его в структуру завернёшь и начнёшь копировать, получится пиздец: одна копия отправила запрос, а другая про это нихуя не знает. Вот тут уже нужен reference type (класс), чтобы все держались за один и тот же объект.

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

Короче, правило простое: по умолчанию — struct. А как только почувствуешь, что данные должны быть разделяемыми и изменяемыми из разных мест — вот тут включай мозг и думай про классы. Всё, вопрос закрыт, можно расходиться.