- Published on
iOS 17 @Observable va @MainActor muammolari
- Authors
- Name
- ShoxruxC
- @iOSdasturchi
Eski Combine usulidagi yordamchi ogohlantirish
Agar siz avval ObservableObject va @Published o'zgaruvchilardan foydalangan bo'lsangiz, bir narsaga ko'p marta guvoh bo'lgansiz: qachonki siz asinxron ma'lumotni orqa oqimda (Background Thread) turib @Published o'zgaruvchiga tenglashtirmoqchi bo'lsangiz, Xcode sizga qip-qizil (yoki binafsharang) ogohlantirish berardi: "Publishing changes from background threads is not allowed; make sure to publish values from the main thread." (Orqa oqimdan UI ni o'zgartirish taqiqlanadi!)
Bu ogohlantirish dasturchilar uchun juda katta yordam edi. Biz darhol xatomizni tushunar va ViewModel klassimizning boshiga bitta @MainActor so'zini yozib qo'yish bilan hamma muammoni hal qilar edik.
// Eski usul (Juda xavfsiz)
@MainActor
class MyViewModel: ObservableObject {
@Published var title = "Salom"
}
@Observable dagi yashirin xavf!
iOS 17 bilan Apple bizga ancha qulay bo'lgan @Observable makrosini taqdim qildi. Endi biz ObservableObject va @Published yozishdan qutuldik.
Lekin bu o'zgarish o'zi bilan bitta yashirin xavfni olib keldi: Yangi @Observable makrosi background thread dan turib UI ni o'zgartirsangiz HAM hech qanday ogohlantirish bermaydi! Dastur oddiygina ishlab turadi, lekin foydalanuvchilar uni ishlatayotganda qotib qolishi yoki birdaniga yopilib ketishi (Crash) mumkin.
Ikkinchi va eng yomon muammo: Endi biz butun boshli ViewModel klassiga @MainActor deya yozolmaymiz! Agar yozsak, @Observable makrosining o'zida kompilyatsiya xatolari kelib chiqadi.
Xo'sh, unda qanday qilib kodimiz asinxron holatda ham doim Asosiy Oqimda (Main Thread) ishlashini kafolatlaymiz?
Yechimlar
Bu muammoni hal qilishning bir necha usullari bor va siz vaziyatga qarab o'zingizga qulayini tanlashingiz mumkin:
1-yechim: O'zgaruvchining o'zini @MainActor qilish
Siz eng muhim, to'g'ridan-to'g'ri Ekrandagi yozuvlarga bog'langan o'zgaruvchilarni alohida @MainActor qilib belgilab qo'yishingiz mumkin. Bu kompilyatorga xatoni ko'rsatishga yordam beradi.
@Observable
class MyViewModel {
// Har bir UI o'zgaruvchi alohida belgilanadi
@MainActor var title: String = "Kutilmoqda..."
func updateTitle() async {
let newTitle = await Database.fetchTitle() // Boshqa oqimda ishlaydi
// Agar bu yerda to'g'ridan to'g'ri 'self.title = newTitle' desangiz
// endi Xcode aniq xato beradi! Chunki title MainActor da.
await MainActor.run {
self.title = newTitle // Xavfsiz usul
}
}
}
2-yechim: Funksiyani @MainActor qilish
Agar siz har bir o'zgaruvchiga yozib chiqishga erinsangiz, funksiyaning o'zini Asosiy Oqimga bog'lab qo'yish ancha qulayroq:
@Observable
class MyViewModel {
var title: String = "Kutilmoqda..."
// Butun boshli funksiya Asosiy Oqimda ishlashiga kafolat
@MainActor
func updateTitle() async {
// Await orqali u orqa oqimga tushib ketadi...
let newTitle = await Database.fetchTitle()
// ...kelgach avtomatik tarzda yana Asosiy Oqimga (MainActor ga) qaytadi!
self.title = newTitle
}
}
3-yechim: Task ichida e'lon qilish
Ko'pincha ViewModel'dagi oddiy sinxron funksiyalardan turib asinxron Task ochamiz. Bunday paytda Task'ning o'zi MainActor'da ishga tushishini ta'minlash eng toza yechim hisoblanadi:
@Observable
class MyViewModel {
var title: String = "Kutilmoqda..."
// View dan chaqiriladigan oddiy funksiya
func onButtonTapped() {
// Task ataylab Asosiy Oqimda ochiladi
Task { @MainActor in
let newTitle = await Database.fetchTitle()
self.title = newTitle // Bu yer ham 100% xavfsiz!
}
}
}
Xulosa
iOS 17 dan boshlab yangi loyihalarda @Observable makrosidan foydalanish qat'iy tavsiya etiladi. Lekin unda eski xavfsizlik ogohlantirishlari ishlamasligini yodda tuting. Doimo UI ni yangilayotgan joyingiz @MainActor da ekanligiga e'tibor bering va yuqoridagi 3 ta yechimning bittasidan faol foydalaning!