
Sebelum adanya async/await pada Swift, kita biasanya menggunakan Completion Handler untuk menjalankan sebuah code setelah suatu task selesai dijalankan.
Completion Handler1func fetchProducts(completion: @escaping ([String]) -> Void) {2 let url = URL(string: "https://website.com/api/products")!34 URLSession.shared.dataTask(with: url) { data, response, error in5 if let data = data {6 if let products = try? JSONDecoder().decode([String].self, from: data) {7 completion(products)8 return9 }10 }1112 completion([])13 }.resume()14}1516fetchProducts { products in17 print(products)18}
Namun, Completion Handler memiliki kekurangan yaitu ketika kita menggunakan nested Completion Handler, code kita akan sulit untuk dibaca karena indentasi code-nya akan semakin dalam, kondisi ini sering disebut sebagai Callback Hell.
Callback HellTapi untungnya Swift memiliki fitur untuk mengubah function yang menggunakan Completion Handler agar menjadi async/await tanpa perlu memodifikasi code asli dari function tersebut dan tanpa perlu rewrite code yang sudah ada. Sehingga kita bisa gunakan fitur tersebut untuk code yang bukan milik kita, dari framework lain misalnya.
Jadi konsepnya, kita akan buat satu function baru untuk membungkus function yang menggunakan Completion Handler tersebut.
Kita akan bungkus menggunakan beberapa functions berikut:
withCheckedContinuation
withCheckedThrowingContinuation
withUnsafeContinuation
withUnsafeThrowingContinuation
Berikut adalah contoh penggunaan withCheckedContinuation:
withCheckedContinuation1func fetchProducts() async -> [String] {2 let url = URL(string: "https://website.com/api/products")!35 return await withCheckedContinuation { continuation in6 URLSession.shared.dataTask(with: url) { data, response, error in7 if let data = data {8 if let products = try? JSONDecoder().decode([String].self, from: data) {10 continuation.resume(returning: products)11 return12 }13 }1416 continuation.resume(returning: [])17 }.resume()18 }19}2021let products = await fetchProducts()
Kita gunakan method continuation.resume(returning:) untuk me-return value.
Ada 2 hal yang harus diperhatikan ketika menggunakan Continuation:
Kita hanya boleh menjalankan method continuation.resume satu kali saja. Jika tidak, maka akan muncul error seperti ini:
1_Concurrency/CheckedContinuation.swift:164: Fatal error: SWIFT TASK CONTINUATION MISUSE: fetchProducts() tried to resume its continuation more than once, returning []!
Kita harus memanggil method continuation.resume. Jika tidak, maka akan muncul error seperti ini:
1SWIFT TASK CONTINUATION MISUSE: fetchProducts() leaked its continuation!
withCheckedThrowingContinuation itu sama seperti function sebelumnya, tapi dia bisa throwing error menggunakan method continuation.resume(throwing:)
Berikut adalah contoh penggunaan withCheckedThrowingContinuation:
withCheckedThrowingContinuation1enum ErrorType: Error {2 case networkError3}45func fetchProducts() async throws -> [String] {6 let url = URL(string: "https://website.com/api/products")!78 return try await withCheckedThrowingContinuation { continuation in9 URLSession.shared.dataTask(with: url) { data, response, error in10 if let data = data {11 if let products = try? JSONDecoder().decode([String].self, from: data) {12 continuation.resume(returning: products)13 return14 }15 }1618 continuation.resume(throwing: ErrorType.networkError)19 }.resume()20 }21}2223do {24 let products = try await fetchProducts()25 print(products)26} catch {27 print(error)28}
Ada 2 tipe Swift Continuations, yaitu Checked (yang telah kita bahas sebelumnya) dan Unsafe.
Bedanya, yang Unsafe itu tidak ada pengecekan-pengecekan pada saat runtime, seperti pengecekan harus memanggil method continuation.resume, dll. sehingga jika ada masalah tidak akan terdeteksi lebih awal dan kita tidak mendapatkan informasi yang jelas pada Crash Log.
Benefit ketika kita menggunakan Unsafe adalah performa aplikasi kita menjadi sedikit lebih cepat, karena tidak ada pengecekan-pengecekan tersebut pada saat runtime.
Apple merekomendasikan kita untuk menggunakan tipe Checked pada saat proses development. Lalu setelah kita berhasil menjalankan code kita tanpa muncul error atau warning, dan setelah kita yakin bahwa code kita sudah benar, maka kita bisa mengubahnya menjadi Unsafe.
Kalau saya sendiri lebih memilih untuk selalu menggunakan Checked, bahkan ketika saya sudah yakin bahwa tidak akan muncul runtime error pada saat pengecekan. Selain karena lebih aman, juga agak repot kalau harus mengganti Checked menjadi Unsafe secara manual dan mengembalikan menjadi Checked lagi apabila saya melakukan perubahan pada code tersebut. 😅
Oke mungkin itu saja yang bisa saya bagikan kali ini, kalau kamu merasa artikel ini bermanfaat silakan Like & Share artikel ini ke teman-teman kamu atau jika kamu punya pertanyaan, tulis aja di kolom komentar, Thank you! 😁 🙏
Always open to new ideas 🕊️
Articles that you might want to read.

Menulis kode yang mudah untuk di-test pada Swift.

Tutorial membongkar dan memodifikasi aplikasi iOS 🍎

Otomatisasi build, testing, screenshot, dan deployment aplikasi iOS ke Testflight & AppStore.