Структура или класс
Теперь у вас две картинки. Структура — бланк: при присваивании делают ксерокопию, и копию заполняют отдельно. Класс — общий документ: к нему ведут бирки, и правку через одну бирку видно через все. Что выбрать, структуру или класс, зависит от того, что должна делать программа.
Возьмём игру. У игрока есть очки, и с ним работают сразу несколько частей программы: команда, таблица рекордов, экран профиля. Очки должны совпадать везде, значит, игрок — один общий экземпляр:
class Player {
var score = 0
}
let hero = Player()
let team = [hero]
hero.score += 5
print(team[0].score) // 5
print(team[0] === hero) // trueДавайте разберём программу:
hero— ссылка на экземплярPlayer.team = [hero]кладёт в массив ещё одну ссылку на тот же экземпляр. Массив копирует ссылку, а не игрока.hero.score += 5меняет общего игрока, поэтомуteam[0].scoreтоже равно5.team[0] === heroотвечаетtrue: это один экземпляр.
А позиция фигуры на поле — это только число. Если сохранить стартовую позицию и потом двигать фигуру, стартовая должна остаться прежней. Здесь нужна копия, то есть структура:
struct Position {
var x = 0
}
let start = Position()
var current = start
current.x += 3
print(start.x, current.x) // 0 3current — копия start, поэтому сдвиг current не трогает start, и программа печатает 0 3.
Как выбрать
Структура — по умолчанию
Apple советует начинать со структуры. Берите её, когда значение описывает данные: позицию, сумму денег, настройки. Каждый, кто получил структуру, работает со своей копией, и никто не изменит её у вас за спиной.
Класс — для общего экземпляра
Берите класс, если верно хотя бы одно:
- несколько частей программы меняют одну и ту же вещь и должны видеть правки друг друга: игрока, банковский счёт, открытый документ;
- важно, тот же это экземпляр или другой с такими же свойствами, то есть нужна проверка
===; - нужно наследование.
Здесь картинка с ксерокопией неточна. Настоящая ксерокопия стоит бумаги, а копия небольшой структуры почти ничего не стоит. Массив внутри неё Swift копирует только перед первым изменением, как вы видели в теме о массивах. Поэтому брать класс, чтобы сэкономить на копиях, не нужно.
Ответ на собеседовании
«Чем структура отличается от класса?» — один из самых частых вопросов на собеседовании по Swift. Ответ можно строить так:
- Структура — значимый тип: присваивание и передача в функцию копируют значение. Класс — ссылочный: копируется ссылка, и все имена ведут к одному экземпляру.
letу структуры замораживает всё значение, а у класса — только ссылку.- Методы структуры, меняющие свойства, помечают
mutating; методам класса это не нужно. - Структура сама получает почленный инициализатор, а классу со свойством без значения по умолчанию пишут свой
init. - Только у классов есть наследование и проверка
===.
Закончите тем, как выбирать: по умолчанию структура, а класс — когда нужен общий экземпляр, проверка === или наследование.
Частая ошибка
Класс взяли для данных, которые должны копироваться. Позицию сохранили, а потом сдвинули фигуру:
class Spot { // ✗
var x = 0
}
let saved = Spot()
let piece = saved
piece.x += 3
print(saved.x) // 3Программа печатает 3, а не 0: let piece = saved скопировала ссылку, и сдвиг фигуры изменил сохранённую позицию. Позиция — это данные, поэтому Spot должен быть структурой. Тогда piece объявляют через var, и программа печатает 0.
Главное
- Структура копируется при присваивании и передаче, а экземпляр класса остаётся общим для всех ссылок.
- По умолчанию выбирают структуру.
- Класс нужен, когда несколько частей программы меняют одну вещь, важна проверка
===или нужно наследование. - Наследование и
===есть только у классов, аmutatingи почленный инициализатор — у структур.