Published on

Continuation yordamida eski kodlarni Async'ga o'tkazish

Authors

Nima uchun Continuation kerak?

Shu paytgacha darslarimizda biz asosan Apple o'zining tayyorlab qo'ygan URLSession.shared.data(from:) asinxron xususiyatidan foydalandik. U allaqachon async/await uchun moslashtirilgan.

Lekin amalda, ilovalar yaratishda juda ko'p uchinchi tomon kutubxonalaridan (SDK) yoki hali yangilanmagan eski bazaviy kodlardan foydalanamiz. Ular odatda ma'lumotni @escaping closure'lar, ya'ni completion handlerlar yordamida qaytaradi. Katta loyihalarda faqatgina 1 ta eski funksiya uchun butun ilova muhitini asinxrondan voz kechishga majburlay olmaymiz. Bunga yechim sifatida, eskirgan funksiyani "zamonashtiradigan" mexanizm mavjud va u Continuation deb ataladi.

Continuation turlari

Sizda funksiyaning turiga qarab asosan 2 ta tanlov bo'ladi:

  1. withCheckedContinuation – Hech qanday xatolik (Error) qaytarmaydigan oddiy operatsiyalar uchun.
  2. withCheckedThrowingContinuation – Xatolik yuzaga kelishi mumkin bo'lgan operatsiyalar uchun. (Kodni ko'proq shu turda yozamiz)

Apple shuningdek, "Unsafe" (xavfsiz bo'lmagan) continuation turlarini ham qo'shgan. Lekin ulardan foydalanish deyarli tavsiya etilmaydi, chunki ular faqatgina kichik samaradorlik (performance) uchun mo'ljallangan va xatolarni tizim qattiq tekshirmaydi. Biz doimo "Checked" turlaridan foydalanamiz.

Eski kodni modernizatsiya qilish misoli

Faraz qilaylik, bizda rasmni ma'lumotlar bazasidan oluvchi va completion handler ishlatadigan eski funksiya bor:

// Eski (SDK) usulidagi funksiya:
func getHeartImageFromDatabase(completionHandler: @escaping (UIImage?, Error?) -> Void) {
    // 5 soniyalik kechikish simulyatsiyasi
    DispatchQueue.main.asyncAfter(deadline: .now() + 5) {
        // Vaqt o'tgach ma'lumot jo'natiladi
        completionHandler(UIImage(systemName: "heart.fill"), nil)
    }
}

Buni qanday qilib ajoyib async funksiyaga aylantirishimiz mumkin? withCheckedThrowingContinuation bloki yordamida!

// Yangilangan (Async/Await) ko'rinishi
func getHeartImageAsync() async throws -> UIImage {

    // Asinxron muhitga Continuation orqali ulanamiz
    return try await withCheckedThrowingContinuation { continuation in

        // Asl (eski) funksiyani ichkarida chaqiramiz
        getHeartImageFromDatabase { image, error in

            // Agar rasm olsak, uni qaytaramiz (resume returning)
            if let image = image {
                continuation.resume(returning: image)
                return
            }

            // Agar xatolik bo'lsa, xatoni uloqtiramiz (resume throwing)
            if let error = error {
                continuation.resume(throwing: error)
                return
            }

            // Hamma holat inobatga olinganiga ishonch hosil qilish uchun qo'shimcha xato
            continuation.resume(throwing: URLError(.badURL))
        }
    }
}

Endi ViewModel ichida biz ushbu toza va muammosiz ishlaydigan yangi funksiyadan osongina foydalanishimiz mumkin bo'ladi:

Task {
    do {
        let image = try await getHeartImageAsync()
        self.image = image
    } catch {
        print(error)
    }
}

🚨 OLTIN QOIDA: Faqat va Faqat BIR marta!

Apple'ning rasmiy hujjatlarida shunday deyilgan: "Siz Continuation.resume funksiyasini AYNAN BIR MARTA (exactly once) chaqirishingiz shart!"

Buning ma'nosi nima?

  • Nol marta (chqirilmasa): Tasavvur qiling, kod yuqoridagi if bloklariga tushmadi va oxirgi uchinchi resume qatori yozilmagan. Natijada resume umuman chaqirilmay qoladi. Bu holda dastur bu Task'ni "Tugadi" deb o'ylamaydi va umrbod xotirada qotib qoladi (Memory Leak)!
  • Ikki marta (yoki undan ko'p): Tasavvur qiling, siz tasodifan hamma joyga resume yozib tashladingiz yoki return so'zini esdan chiqardingiz. Agar bitta Continuation ichida ikki marta resume ishlansa, dastur (App) to'g'ridan-to'g'ri CRASH bo'ladi (qulaydi). Tizim buni darhol fosh qiladi.

Shuning uchun, Continuation yozayotganingizda doimo barcha mantiqiy yo'llar (if, else, switch) oxir-oqibat faqatgina bitta o'z vaqtida chqiriladigan resume ga borib ulanishiga 100% ishonch hosil qiling!

Buy mea coffee