Məzmuna keç
Educora
İrəli22 dəq11 / 14

Vəziyyət və verilənlərin axını

SwiftUI-də vəziyyəti `@State` ilə saxla, onu `@Binding` ilə uşaq görünüşlərə ötür, modeli `@Observable` makrosu ilə yarat, `@Environment` ilə paylaş və tətbiqi MVVM üslubunda qur.

Özünü yoxla
Bu dərsdə öyrənəcəksən
  • @State və @Binding-in fərqini izah etmək və vahid həqiqət mənbəyini tapmaq
  • @Observable makrosu ilə model sinfi yaratmaq və onu @State ilə saxlamaq
  • @Environment və @Bindable ilə modeli görünüşlər arasında paylaşmaq
  • SwiftUI-də MVVM qatlarını təsvir etmək

Nigar parametrlər ekranında gündəlik məqsədini 15 dəqiqədən 30-a qaldırır, amma əsas ekranda hələ də «15 min» yazılıb. Səbəb sadədir: eyni qiymət iki yerdə saxlanılıb və onlar bir-birindən xəbərsizdir. SwiftUI-də qızıl qayda belədir: hər məlumatın bir sahibi — vahid həqiqət mənbəyi olmalıdır, qalan görünüşlər isə onu oxumalı və ya ona bağlanmalıdır. Bu dərsdə bunun üçün alətləri öyrənəcəksən.

@State: görünüşün öz vəziyyəti

View strukturu dəyişməzdir və SwiftUI onu istənilən an yenidən yarada bilər. Ona görə dəyişən qiymət adi xassədə saxlanıla bilməz. @State SwiftUI-dən qiyməti strukturdan kənarda saxlamağı və dəyişəndə body-ni yenidən hesablamağı xahiş edir. @State xassəsini həmişə private elan et: o, yalnız bu görünüşə məxsusdur. İlkin qiymət yalnız bir dəfə, görünüş ekranda ilk dəfə yarananda götürülür; sonra SwiftUI öz saxladığı qiymətdən istifadə edir.

Səhv: adi xassə
struct CounterView: View {
    var count = 0

    var body: some View {
        Button("Taps: \(count)") {
            count += 1
        }
    }
}
Düzgün: @State
struct CounterView: View {
    @State private var count = 0

    var body: some View {
        Button("Taps: \(count)") {
            count += 1
        }
    }
}
Soldakı kod kompilyasiya olunmur: «Cannot assign to property: 'self' is immutable». Sağda hər toxunuş sayğacı artırır və ekranı yeniləyir.

@Binding: başqasının vəziyyətinə bağlantı

Uşaq görünüş valideynin qiymətini dəyişməlidirsə, ona surət yox, binding — iki tərəfli bağlantı verilir. Valideyn qiyməti $ ilə ötürür ($goal), uşaq isə onu @Binding kimi elan edir. Uşaq qiyməti dəyişəndə əslində valideynin @State-i dəyişir və ekranın hər iki hissəsi eyni anda yenilənir.

Swift
struct GoalStepper: View {
    @Binding var minutes: Int

    var body: some View {
        Stepper("Daily goal: \(minutes) min", value: $minutes, in: 5...60, step: 5)
    }
}

struct SettingsScreen: View {
    @State private var goal = 15

    var body: some View {
        Form {
            GoalStepper(minutes: $goal)
            Text("You will study \(goal) minutes a day")
        }
    }
}
Ekranda: +/− düyməli sətir və altında mətn; düyməyə basanda hər iki sətirdəki rəqəm birlikdə dəyişir.
Tərif
Vahid həqiqət mənbəyi

Məlumatın saxlandığı yeganə yer. Nümunədə bu, SettingsScreen-dəki @State private var goal-dur; GoalStepper isə yalnız ona bağlanır və öz surətini saxlamır.

@Observable modellər

Ekranın məlumatı və məntiqi çoxalanda onları ayrıca model sinfinə köçürürük. iOS 17-dən başlayaraq sinfin qarşısına @Observable makrosunu yazmaq kifayətdir: SwiftUI body-də oxunan xassələri özü izləyir və yalnız onlar dəyişəndə görünüşü yeniləyir. Modelin məntiqini ekransız, adi Swift kodu ilə də yoxlamaq olar:

Swift
import Observation

@Observable
final class QuizModel {
    var question = 1
    var score = 0
    var finished: Bool { question > 5 }

    func answer(correct: Bool) {
        if correct { score += 1 }
        question += 1
    }
}

let quiz = QuizModel()
for correct in [true, false, true, true, true] {
    quiz.answer(correct: correct)
}
print("Score: \(quiz.score) / 5, finished: \(quiz.finished)")
Gözlənilən nəticə
Score: 4 / 5, finished: true
Swift
struct QuizView: View {
    @State private var quiz = QuizModel()

    var body: some View {
        VStack(spacing: 16) {
            if quiz.finished {
                Text("Your score: \(quiz.score) / 5")
            } else {
                Text("Question \(quiz.question) of 5")
                Button("Correct") { quiz.answer(correct: true) }
                Button("Wrong") { quiz.answer(correct: false) }
            }
        }
        .font(.title2)
    }
}
Ekranda: «Question 1 of 5» və iki düymə; beşinci cavabdan sonra «Your score: 4 / 5» kimi nəticə.
Köhnə: ObservableObject (iOS 13+)
final class QuizModel: ObservableObject {
    @Published var score = 0
}

struct QuizView: View {
    @StateObject private var quiz = QuizModel()
    // child views: @ObservedObject, @EnvironmentObject
}
Yeni: @Observable (iOS 17+)
@Observable
final class QuizModel {
    var score = 0
}

struct QuizView: View {
    @State private var quiz = QuizModel()
    // child views: plain property, @Bindable, @Environment
}
Köhnə üsulda hər xassəyə @Published yazmaq lazım idi və obyektin istənilən dəyişikliyi onu izləyən bütün görünüşləri yeniləyirdi. @Observable daha az kod tələb edir və yalnız həqiqətən oxunan xassələrə reaksiya verir.

@Environment və @Bindable

Modeli beş səviyyə aşağıdakı görünüşə parametrlər zənciri ilə ötürmək yorucudur. Bunun əvəzinə onu .environment(profile) ilə mühitə qoyuruq, lazım olan görünüş isə @Environment(Profile.self) private var profile ilə götürür. Modelin xassəsinə binding lazımdırsa (məsələn, TextField üçün), @Bindable işlədilir. @Environment həm də sistem qiymətlərini verir: \.dismiss, \.colorScheme, \.locale.

Swift
@Observable
final class Profile {
    var name = "Nigar"
}

struct ProfileEditor: View {
    @Bindable var profile: Profile

    var body: some View {
        TextField("Name", text: $profile.name)
    }
}

struct GreetingView: View {
    @Environment(Profile.self) private var profile

    var body: some View {
        Text("Hello, \(profile.name)!")
    }
}
Kök görünüş @State private var profile = Profile() saxlayır və .environment(profile) çağırır. Sahədə adı dəyişəndə «Hello, …!» yazısı dərhal yenilənir.
VasitəNə vaxt
@Stategörünüş qiymətin və ya @Observable modelin sahibidir
@Bindinguşaq valideynin qiymətini oxuyur və dəyişir
@Bindable@Observable modelin xassələrinə binding lazımdır
@Environmentsistem qiymətini və ya mühitə qoyulmuş modeli oxumaq
adi letgörünüş qiyməti yalnız göstərir

Bütün bunlar birlikdə MVVM üslubunu yaradır: Model — məlumat strukturları və xidmətlər (şəbəkə, verilənlər bazası); ViewModel — ekranın vəziyyətini və məntiqini saxlayan @Observable sinif (QuizModel); View — vəziyyəti göstərən və istifadəçinin hərəkətlərini ViewModel-in metodlarına ötürən SwiftUI strukturu. İnterfeys yalnız əsas axında yenilənməli olduğu üçün ViewModel-ləri adətən @MainActor ilə işarələyirlər.

  1. 1
    Model faylı yarat

    Cmd+N bas, iOS bölməsində Swift File seç, adını QuizModel qoy və Create bas. Oraya @Observable sinfini yaz.

  2. 2
    Görünüş faylı yarat

    Yenə Cmd+N, bu dəfə SwiftUI View şablonu; adı QuizView. Şablon #Preview blokunu da özü əlavə edir.

  3. 3
    Kətanda yoxla

    Önizləmədə düymələrə bas və sualın nömrəsinin, sonda isə nəticənin dəyişdiyini yoxla — simulyatoru işə salmağa ehtiyac yoxdur.

yeni fayl yaratmaqCmd+N
tipin və ya funksiyanın elanına keçmək — Jump to DefinitionCtrl+Cmd+J
faylın quruluşu: xassələr və metodlar siyahısıCtrl+6
açıq faylı Navigator-da göstərməkCmd+Shift+J

Əsas fikirlər

  • Hər məlumatın bir sahibi olmalıdır — vahid həqiqət mənbəyi.
  • @State private var görünüşün öz vəziyyətidir; dəyişəndə body yenidən hesablanır.
  • @Binding valideynin qiymətinə iki tərəfli bağlantıdır və $ ilə ötürülür.
  • @Observable sinif (iOS 17+) oxunan xassələri özü izləyir; modeli @State ilə saxla, @Environment və @Bindable ilə paylaş.
  • MVVM: Model məlumat verir, @Observable ViewModel vəziyyəti idarə edir, View onu göstərir.

Özünü yoxla

10 sual. Hər düzgün cavab XP qazandırır.

1 / 10
Görünüşün özünə məxsus, dəyişən sadə qiymət necə elan olunur?