SwiftUI 7: SwiftUI ichki arxitekturasi — View identifikatsiyasi, Observation va UIKit bilan aloqa
📱 UIKit va SwiftUI — chuqur
SwiftUI 7: SwiftUI ichki arxitekturasi — View identifikatsiyasi, Observation va UIKit bilan aloqa
Holat: 2026-yil sentabr. SwiftUI oddiy deklarativ sintaksisdek ko'rinsa-da, uning kapoti ostida murakkab graf nazariyasi va identifikatsiya algoritmlari yotadi. Nega ba'zida
@Stateo'z-o'zidan nolga tushib qoladi? Nega view keraksiz qayta chiziladi? Ushbu darsda Strukturaviy va Aniq identifikatsiya, Observation (@Observable) ning xotira darajasidagi ishlashi hamda UIKit bilan ikki tomonlama integratsiya ko'rib chiqiladi.
Mundarija
- View identifikatsiyasi: Strukturaviy vs Aniq (Explicit)
- Identifikatorning xotira hayot davriga ta'siri
- Observation Framework (@Observable) evolyutsiyasi
- body qachon qayta ishga tushadi: _printChanges()
- UIKit'ni SwiftUI'ga olib kirish: UIViewRepresentable
- SwiftUI'ni UIKit'ga olib kirish: UIHostingController
- Zamonaviy kataklar: UIHostingConfiguration
- Xulosa
- Manbalar
1. View identifikatsiyasi: Strukturaviy vs Aniq (Explicit) {#identity}
SwiftUI'da view struktura bo'lgani sababli, uning xotira manzili (pointer) doimiy emas. Tizim qaysi view o'zgarganini bilish uchun ikki xil identifikatsiyadan foydalanadi:
1. Strukturaviy identifikatsiya (Structural Identity)
View daraxtidagi ierarxik o'rni orqali aniqlanadi. Masalan:
import SwiftUI
struct ConditionalView: View {
var isFlag: Bool
var body: some View {
if isFlag {
CounterView() // Shox A (Identifikator: ConditionalView.True)
} else {
CounterView() // Shox B (Identifikator: ConditionalView.False)
}
}
}
struct CounterView: View {
@State private var count = 0
var body: some View {
Button("Bosildi: \(count)") { count += 1 }
}
}
Tuzoq: Garchi ikkala shoxda ham
CounterView()yozilgan bo'lsa-da,isFlago'zgarganda SwiftUI eski shoxdagi view'ni butunlay o'chiradi va yangi shoxdagisini yaratadi — natijada@State var count0 ga aylanib qoladi!
2. Aniq identifikatsiya (Explicit Identity)
Dasturchi tomonidan .id(...) yoki ForEach(items, id: \.id) orqali beriladigan qat'iy identifikator.
2. Identifikatorning xotira hayot davriga ta'siri {#identity-lifetime}
Agar siz biror view'ning holatini majburan noldan tozalab, animatsiya bilan qayta ishga tushirmoqchi bo'lsangiz, uning .id(...) sini o'zgartirish kifoya:
import SwiftUI
struct ProfileResetContainer: View {
@State private var sessionID = UUID()
var body: some View {
VStack {
ProfileDetailsView()
.id(sessionID) // sessionID o'zgarsa, ichki barcha State tozalanadi
Button("Sessiyani yangilash") {
sessionID = UUID()
}
}
}
}
struct ProfileDetailsView: View {
@State private var text = "Qoralama"
var body: some View {
TextField("Matn", text: $text)
}
}
3. Observation Framework (@Observable) evolyutsiyasi {#observation}
iOS 17 dan boshlab (va iOS 26/27 da to'liq standart) Swift Syntax Makroslariga asoslangan Observation Framework kiritildi:
- **Eski usul (
ObservableObject+@Published):** Ob'ekt ichidagi istalgan bitta@Publishedmaydon o'zgarsa ham, butun view to'liq qayta hisoblanar edi. - **Zamonaviy usul (
@Observable): Tizim maydon darajasida kuzatuv (Property-level tracking**) olib boradi.
import SwiftUI
@Observable
public final class UserProfileModel {
public var name: String = "Azimjon"
public var age: Int = 26
public var lastLogin: Date = Date()
}
public struct UserProfileView: View {
@Bindable public var model: UserProfileModel
public var body: some View {
VStack(spacing: 8) {
// Faqat name o'qilmoqda:
Text(model.name)
TextField("Ism", text: $model.name)
}
}
}
Agar fonda model.age yoki model.lastLogin qiymati o'zgarsa, UserProfileView qayta chizilmaydi, chunki uning bodysi faqat name ga bog'langan! Bu xotira va CPU sarfini keskin tejaydi.
4. body qachon qayta ishga tushadi: _printChanges() {#body-evaluation}
SwiftUI'da body quyidagi 4 holatda qayta hisoblanadi:
- View'ning o'z
@Stateo'zgaruvchisi o'zgarganda; bodyichida o'qilgan@Observablemodeli maydoni o'zgarganda;@Environmentqiymati (masalan, rang mavzusi) yangilanganda;- Ota ko'rinishdan uzatilgan tashqi parametr o'zgarganda.
Nosozliklarni qidirish (Debugging):
Qaysi sababga ko'ra ko'rinish qayta chizilayotganini bilish uchun maxsus yashirin metoddan foydalaniladi:
import SwiftUI
struct DebuggingView: View {
@State private var count = 0
var body: some View {
#if DEBUG
let _ = Self._printChanges()
#endif
Button("Soni: \(count)") {
count += 1
}
}
}
Xcode konsolida: DebuggingView: @self, _count changed. degan aniq diagnostika chiqadi.
5. UIKit'ni SwiftUI'ga olib kirish: UIViewRepresentable {#uiview-representable}
SwiftUI'da hali mavjud bo'lmagan yoki murakkab UIKit komponentlarini (masalan, maxsus datchiklar, WebView yoki kamera ko'rinishi) SwiftUI'ga o'rash:
import SwiftUI
import UIKit
public struct NativeSpinner: UIViewRepresentable {
public var isSpinning: Bool
public func makeUIView(context: Context) -> UIActivityIndicatorView {
UIActivityIndicatorView(style: .medium)
}
public func updateUIView(_ uiView: UIActivityIndicatorView, context: Context) {
if isSpinning {
uiView.startAnimating()
} else {
uiView.stopAnimating()
}
}
}
6. SwiftUI'ni UIKit'ga olib kirish: UIHostingController {#hosting-controller}
Mavjud UIKit arxitekturasidagi ekran ichiga yangi SwiftUI modulini joylashtirish:
import SwiftUI
import UIKit
@MainActor
func embedSwiftUIView(in parentVC: UIViewController) {
let swiftUIView = Text("Salom SwiftUI!")
let hostingController = UIHostingController(rootView: swiftUIView)
parentVC.addChild(hostingController)
hostingController.view.frame = CGRect(x: 20, y: 100, width: 300, height: 100)
parentVC.view.addSubview(hostingController.view)
hostingController.didMove(toParent: parentVC)
}
7. Zamonaviy kataklar: UIHostingConfiguration {#hosting-configuration}
iOS 16+ dan boshlab UITableViewCell yoki UICollectionViewCell ichida maxsus subview yaratish shart emas — to'g'ridan-to'g'ri **UIHostingConfiguration** orqali SwiftUI ko'rinishini katakka o'rnatish mumkin:
import SwiftUI
import UIKit
@MainActor
func configureCustomCell(cell: UITableViewCell, title: String) {
cell.contentConfiguration = UIHostingConfiguration {
HStack {
Image(systemName: "checkmark.seal.fill")
.foregroundStyle(.blue)
Text(title)
.font(.body)
Spacer()
}
.padding(.horizontal, 16)
}
}
8. Xulosa {#xulosa}
- Strukturaviy identifikatsiya view daraxtidagi shoxlarga bog'liq; shartli bloklarda (
if-else) holat yo'qolib ketmasligi uchun ehtiyot bo'lish lozim. .id(...)identifikatori o'zgarganda SwiftUI ob'ektni xotiradan to'liq tozalab, qayta tiklaydi.@Observablemakrosi faqatbodyichida real o'qilgan maydonlarni kuzatadi va unumdorlikni keskin oshiradi.Self._printChanges()orqali keraksiz qayta chizilish sabablarini tezkor aniqlash mumkin.UIHostingConfigurationUIKit ro'yxatlarida SwiftUI afzalliklaridan foydalanishning eng zamonaviy usulidir.