Код-ревью Middle SwiftUI обновлено
Код-ревью: экран профиля на SwiftUI
Вопрос
Найдите проблемы в экране профиля.
struct ProfileScreen: View {
@ObservedObject var vm = ProfileViewModel()
@State var formatter = DateFormatter()
var body: some View {
let posts = vm.posts.sorted { $0.date > $1.date }
List {
ForEach(posts.indices, id: \.self) { i in
PostRow(post: posts[i])
}
}
.onAppear {
Task { await vm.load() }
}
}
}
Коротко
Исправленный вариант: @State private var vm = ProfileViewModel() с @Observable @MainActor final class, модель отдаёт уже отсортированные posts, ForEach(vm.posts) { PostRow(post: $0) } с Identifiable, загрузка в .task, форматтер статический.
Что должен найти ревьюер
- Ошибкастрока 2
@ObservedObjectс инициализацией на месте: при пересоздании структуры родителем view model создаётся заново и данные теряются. Нужен@StateObject(или@Stateс@Observable). - Стильстрока 3
@Stateбезprivateи для объекта, который не является состоянием экрана: форматтер лучше статическим или в модели. - Производительностьстрока 6Сортировка в
bodyвыполняется при каждом пересчёте. Сортированный список должна готовить модель. - Ошибкастрока 8Индексы как
id: при удалении или вставке строки анимации и состояниеPostRowуедут на чужие посты. - Ошибкастрока 12
onAppearсTaskне отменяет загрузку при уходе и запускает её при каждом появлении. Нужен.task { await vm.load() }.
Разбор
Исправленный вариант: @State private var vm = ProfileViewModel() с @Observable @MainActor final class, модель отдаёт уже отсортированные posts, ForEach(vm.posts) { PostRow(post: $0) } с Identifiable, загрузка в .task, форматтер статический.
Ответьте сами, а не прочитайте
В тренажёре вопрос попадёт в повторения и вернётся, когда начнёт забываться. Плюс билеты с зачётом: 20 вопросов, не больше 2 ошибок.