Как исправить проблему, когда счетчик в SwiftUI не увеличивается при нажатии кнопки?
Что проверяют
Понимаете ли вы, как SwiftUI узнаёт, что пора перерисовать экран, и кто владеет состоянием. Баг в такой задаче почти всегда про владение или про копию значения, и следом просят объяснить разницу между @State, @Binding и @StateObject.
Как отвечать
Покажите, что идёте по списку причин, а не угадываете:
- значение не источник истины: обычный
varв структуреViewменять нельзя, компилятор не даст. Если модель это класс сObservableObject, свойство должно быть@Published, иначе значение меняется, а экран об этом не знает; - модель пересоздаётся:
@ObservedObject var vm = CounterViewModel()внутри вью создаёт новый объект при каждой перерисовке родителя, и счётчик сбрасывается в ноль. Владелец объявляет@StateObject, а с макросом@Observable(iOS 17 и новее) это@State var vm = CounterViewModel(); - меняется копия: дочерней вью передали
count, а не$count, и она крутит свою копию. Нужен@Binding. Сюда же@State, заданный вinitиз параметра: он инициализируется один раз и потом игнорирует новые значения от родителя; - класс в
@Stateбез@Observable:@Stateотслеживает только ссылку, изменения внутри старогоObservableObjectон не видит; - сбрасывается идентичность вью:
.id(UUID())или веткаif/else, которая пересоздаёт вью, обнуляют всё её состояние; - кнопка в строке
ListилиForm: несколько кнопок в одной строке срабатывают вместе, и «плюс» с «минусом» гасят друг друга. Лечится.buttonStyle(.borderless).
Для диагностики удобно вызвать Self._printChanges() в body: он пишет в консоль, что именно вызвало перерисовку.
Где спотыкаются
Отвечают «добавлю @State» и на этом останавливаются. Интервьюер ждёт разбора, почему не работало, а не рабочий пример счётчика.
Путают @StateObject и @ObservedObject. Разница в том, кто владеет объектом, и из неё вытекает сброс состояния при перерисовке родителя.
Смешивают старую и новую модель наблюдения: помечают класс @Observable, но по привычке тянут к нему @Published и @StateObject, а потом не могут объяснить, какой механизм на самом деле обновляет экран.