Irbisa · Шпаргалка
Состояние в SwiftUI
@State, @Binding, @StateObject, @ObservedObject, @EnvironmentObject, Observation
Чем
@Stateотличается от@Bindingв SwiftUI?struct CounterScreen: View { @State private var count = 0 // owned here var body: some View { VStack { Text("\(count)")…Что в этой вью означают
count,$countи_count?struct CounterView: View { @State private var count: Int init(start: Int = 0) { _count = State(initialValue: start) } var body: some View { VStack { Text("\(count)") Stepper("Count", value: $count) Button("Reset") { count = 0 } } }}Чем отличаются
@Environment,@EnvironmentObjectи@ObservedObject, и когда брать environment вместоinit?@Observablefinal class AppSession { var userName: String?} @main…Какие значения
@Environmentвы реально используете? Например, как дочерняя вью закрывает свой экран?struct EditNoteScreen: View { @Environment(\.dismiss) private var dismiss @Environment(\.scenePhase) private var scenePhase @State private var text = "" var body: some View {…Кнопка Done на клавиатуре формы ничего не делает, а Next не переводит на следующее поле. Какой property wrapper забыли?
struct SignUpForm: View { enum Field { case email, password } @State private var email = "" @State private var password = "" @FocusState private var focused: Field?…Родитель меняет
startс 0 на 5, аCounterпродолжает показывать 0. Почему и как исправить?struct Counter: View { @State private var count: Int init(start: Int) { _count = State(initialValue: start) } var body: some View { Button("\(count)") { count += 1 } }} // In the parent:// Counter(start: selectedPreset.start)Когда использовать
@StateObject, а когда@ObservedObject, и что сломается, если выбрать не тот?final class CartViewModel: ObservableObject { @Published var items: [String] = []} // Owner: created once, kept for the view's lifetimestruct CartScreen: View {…Что делает
@Publishedи какObservableObjectсообщает об изменениях?import Combine final class SearchModel: ObservableObject { @Published var query = "" private var bag = Set<AnyCancellable>()…Найдите баг: по нажатию товар добавляется в корзину, но счётчик корзины в тулбаре не меняется.
final class Cart: ObservableObject { @Published var items: [Product] = [] }final class ShopModel: ObservableObject { @Published var cart = Cart() } struct ShopScreen: View { let products: [Product] @StateObject private var model = ShopModel() var body: some View { List(products) { p in Button(p.name) { model.cart.items.append(p) } } .toolbar { Text("Cart: \(model.cart.items.count)") } }}Что меняет макрос
@Observableпо сравнению сObservableObjectи@Published?@Observablefinal class FeedModel { var title = "Feed" var posts: [Post] = [] @ObservationIgnored var lastRequestID: UUID? // not tracked}…Что такое
@Bindableи когда он нужен с моделью@Observable?@Observablefinal class Profile { var name = "" var isPublic = false}…Вы нажимаете кнопку, а текст не меняется. Почему и как исправить?
final class Draft { var title = ""} struct Editor: View { @State private var draft = Draft() var body: some View { VStack { Text(draft.title.isEmpty ? "empty" : draft.title) Button("Set") { draft.title = "Hello" } } }}Как выбрать правильный property wrapper для куска состояния в SwiftUI?
Как передать дочерней вью
Binding, если значение не хранится в@State?struct ProfileEditor: View { let user: User // @Observable class with age: Int @State private var nickname: String? var body: some View { Form {…Правки на экране деталей не появляются в списке позади него, хотя оба показывают одну и ту же структуру
Order. Что пошло не так?struct Order: Identifiable { let id: UUID; var note: String } // wrong: the detail edits a private copystruct CopyDetail: View { @State private var order: Order init(order: Order) { _order = State(initialValue: order) }…Когда SwiftUI заново выполняет
bodyвью и когда сбрасывается её@State?struct EditorScreen: View { @State private var isEditing = false var body: some View { // Two branches = two views: switching resets FormView's @State if isEditing {…Состояние «развёрнуто/свёрнуто» у строки сбрасывается, когда пользователь прокручивает её за экран и обратно. Что на самом деле происходит?
struct Feed: View { let items: [Item] @State private var expanded: Set<Item.ID> = [] // survives rows being discarded var body: some View { List(items) { item in…Где во вью SwiftUI место для побочных эффектов и асинхронной работы и что происходит с
.task, когда вью исчезает?struct SearchScreen: View { @State private var query = "" @State private var results: [Hit] = [] let api: SearchAPI var body: some View {…Что делают
@AppStorageи@SceneStorageи где они перестают быть подходящим инструментом?enum Theme: String, CaseIterable { case system, light, dark } struct SettingsView: View { @AppStorage("showBadges") private var showBadges = true @AppStorage("theme") private var theme: Theme = .system // RawRepresentable @SceneStorage("draftNote") private var draftNote = "" // restored per window…Как
@Observableузнаёт, какие вью инвалидировать, и какие изменения это отслеживание молча пропускает?// Roughly what @Observable generates for one propertyfinal class Model: Observable { @ObservationIgnored private var _title = "" @ObservationIgnored private let registrar = ObservationRegistrar() var title: String {…Модель пишет свои свойства из фонового сетевого колбэка, и список обновляется с опозданием, глючит или падает. Чего на самом деле требует SwiftUI?
// wrong: writes an observed property from a background callback@Observable final class BadFeed { var items: [Item] = [] func load(_ url: URL) { URLSession.shared.dataTask(with: url) { data, _, _ in self.items = decode(data) // background thread: data race…Найдите баг: чат-сервер фиксирует новое подключение при каждой перерисовке родительского экрана, хотя у пользователя открыт один чат.
// ChatSocket wraps a WebSocket: connect() opens it, disconnect() closes it, messages() streams incoming text@MainActor @Observable final class ChatModel { var messages: [String] = [] private let socket = ChatSocket(url: supportURL) init() { Task { // bug: side effects in init socket.connect() for await message in socket.messages() { messages.append(message) } } }} struct SupportChatScreen: View { @State private var model = ChatModel() var body: some View { List(model.messages, id: \.self) { Text($0) } }}Экран на SwiftUI подтормаживает, и вы подозреваете слишком частые вычисления body. Как это подтвердить и что менять?
struct CartRow: View { let item: CartItem var body: some View { let _ = Self._printChanges() // debug only: prints `@self`, `@identity` or the changed property Text(item.title)…Как организовать владение состоянием и поток данных в большом SwiftUI-приложении?