Published on

Combine'dan Async Await'ga o'tish (@Published)

Authors

Combine va @Published ga qisqacha nazar

Agar siz SwiftUI va Combine bilan ishlagan bo'lsangiz, albatta @Published kalit so'ziga ko'p bora duch kelgansiz. Odatda, u ViewModel yoki Manager klasslarida ma'lumotlar o'zgarganini kuzatib borish uchun ishlatiladi.

Eski Combine usuli: Bunday o'zgaruvchilarni "tinglash" (kuzatish) uchun biz Combine ning sink funksiyasidan foydalanardik va obunani AnyCancellable to'plamida saqlashga majbur edik:

class MyViewModel: ObservableObject {
    @Published var dataArray: [String] = []
    var cancellables = Set<AnyCancellable>()

    func addSubscribers() {
        // Eski usul (Combine)
        dataManager.$myData
            .receive(on: DispatchQueue.main)
            .sink { [weak self] returnedData in
                self?.dataArray = returnedData
            }
            .store(in: &cancellables)
    }
}

Biroq, zamonaviy Swift Concurrency (Async/Await) davrida butun kodimiz qulay Task va await lar ustiga qurilgan paytda, faqat bitta o'zgaruvchini tinglash uchun buncha Combine kodini yozish va xotirada ushlab turish biroz noqulay.

Xo'sh, buni oddiyroq yo'li bormi? Albatta!

.values (AsyncPublisher) bilan tanishing

Apple bizga Combine o'zgaruvchilarini zamonaviy asinxron shaklga o'tkazib beruvchi bitta sehrli xususiyatni taqdim etgan. U .values deb ataladi. U @Published o'zgaruvchini avtomatik ravishda AsyncPublisher (Asinxron xabar tarqatuvchi) ga aylantirib beradi.

Qani endi xuddi shu amalni zamonaviy Concurrency usulida qanday yozilishini ko'ramiz:

class MyViewModel: ObservableObject {
    @Published var dataArray: [String] = []

    func addSubscribers() {
        Task {
            // Combine o'rniga oddiy Asinxron Sikl (for await) ishlatiyapmiz!
            for await value in dataManager.$myData.values {

                // UI (ekran) ni yangilayotganimiz uchun MainActor'ga o'tamiz
                await MainActor.run {
                    self.dataArray = value
                }
            }

            // 🚨 DIQQAT: Bu yerdagi kod umuman ISHLAMAYDI! 🚨
            print("Loop tugadi!")
        }
    }
}

Muhim Ogohlantirish! (Abadiy Sikl)

Yuqoridagi kodga diqqat qiling: for await value in ... qatori bu oddiy for sikli emas. Oddiy for massivdagi barcha narsalarni sanab o'tib tugaydi.

Lekin biz bu yerda Publisher'ni (Tarqatuvchini) eshityapmiz. Publisher qachon yangi xabar kelishini bilmaydi, shuning uchun u kutishni hech qachon to'xtatmaydi. Natijada, ushbu sikl umrbod yashaydi va sikldan keyin keladigan qatorlar (masalan print kodi) hech qachon bajarilmaydi!

Agar sizga qachondir siklni to'xtatish va davom etish kerak bo'lsa, qandaydir shartlar asosida break kalit so'zini ishlatib siklni buzib chiqishingiz shart. Lekin aksariyat hollarda (ma'lumotlarni doimiy sinxronlashda) bu abadiy sikl biz uchun juda foydali hisoblanadi.

Xulosa

Apple borgan sari eskirib borayotgan Combine freymvorkini asta-sekin Swift Concurrency'ga singdirib yubormoqda. Tez orada Combine ning barcha mashhur operatorlari (map, debounce, combineLatest va boshqalar) AsyncSequence va AsyncAlgorithms paketlari orqali Async/Await uslubiga o'tishi kutilmoqda.

Shunday ekan, @Published o'zgaruvchilarini kuzatishning eng zo'r va ixcham usuli aynan ushbu .values orqali asinxron sikl yaratishdir!

Buy mea coffee