Почему использовать геттеры и сеттеры вместо прямого доступа к свойствам
Что проверяют
Отличаете ли вы инкапсуляцию от механического обкладывания полей методами. В Swift обращение к хранимому и к вычисляемому свойству выглядит одинаково, поэтому вопрос не про синтаксис, а про то, какие инварианты вы защищаете и какими средствами языка.
Как отвечать
Скажите главное: в Swift не пишут getName() и setName(), потому что свойство само по себе точка расширения. Хранимое свойство можно позже превратить в вычисляемое или навесить наблюдателя, и ни одна строка вызывающего кода не изменится. Значит выбор стоит не между полем и методами, а между «контроль нужен» и «не нужен».
Контроль нужен там, где есть инвариант: допустимый диапазон, производная величина, которая не должна разойтись с источником, реакция на изменение.
final class Cart {
private(set) var items: [Item] = []
var total: Decimal { items.reduce(0) { $0 + $1.price } }
func add(_ item: Item) { items.append(item) }
}private(set) оставляет чтение открытым, а запись закрывает. total вычисляется, поэтому рассинхронизировать её с содержимым невозможно в принципе. Из того же набора инструментов: willSet и didSet для реакции на изменение, lazy var для дорогой инициализации по требованию, уровни доступа для границы модуля.
Заканчивать стоит обратной стороной: если инварианта нет, открытое свойство честнее обёртки, оно не обещает того, чего не делает.
Где спотыкаются
Переносят привычки Java и заводят пары методов вокруг каждого поля. В Swift это лишний слой: тот же результат даёт вычисляемое свойство, а вызывающий код остаётся естественным.
Пишут аксессор, который ничего не проверяет, и считают, что инкапсуляция достигнута. Геттер, возвращающий поле как есть, и сеттер, присваивающий значение без условий, добавляют строки и ни одной гарантии.
Прячут в сеттер обработку некорректного значения через вывод в консоль. Вызывающий код уверен, что запись прошла, а она молча проигнорирована. Либо отвергать явно, бросающим методом или Result, либо приводить к допустимому и описывать это как поведение. Рядом ловушка: didSet не срабатывает на присваивание внутри init.