İçeriğe geç

Swift 5.5 ile Async/await kullanımı

Merhabalar bu yazımda Swift 5.5 ile aramıza katılacak olan oldukça güzel bir ekleme olan Async/await konusundan bahsedeceğim.

Her yıl Swift ekibi geliştirdikleri yeni sürümü bizlere sunmaktalar. WWDC sonrası Xcode 13 Beta biz geliştiricilere sunulmuş oldu. Bu yazıda ve bundan sonraki yazacağım yeni versiyon örneklerini beta sürümünde test edebilirsiniz.

Bu yeni Swift versiyonundaki en önemli ve değerli geliştirme bana göre Async/await konusu oldu. Javascript ve C# gibi dillerde olan bu özellik, Swift dilinede eklendi.

Bu yeni kullanım ile iç içe geçmiş gereksiz closure kullanımından kurtulacağız. Daha okunaklı ve işlemleri düzgün yürüten asenkron bir yapı karşımızda olacak. Swift 5 ile aramıza katılan Result tanımlayıcısı ile closure ile gerçekleştirilen işlemler daha kolaylaşsada zincirleme olarak iç içe geçen ve karışan error handling işlemleri daha temiz ve okunaklı bir hal alacak.

fetchWeatherHistory { records in
    calculateAverageTemperature(for: records) { average in
        upload(result: average) { response in
            print("Server response: \(response)")
        }
    }
}

gibi bir kullanım yerine. Aşağıdaki yeni kullanım daha temiz olduğunu görebilirsiniz.

func processWeather() async {
    let records = await fetchWeatherHistory()
    let average = await calculateAverageTemperature(for: records)
    let response = await upload(result: average)
    print("Server response: \(response)")
}

Aşağıda yazdığım örnekte SwiftUI ile kullanımını inceleyebilirsiniz.

struct TodosModel: Codable, Identifiable, Hashable {
    var userId: Int
    var id: Int
    var title: String = ""
    var completed: Bool = false
}

enum FailureReason : Error {
    case urlFailed
    case decodingFailed
    case responseFailed
}
class ContentVM: ObservableObject {
        
    func getTodos() async throws -> [TodosModel] {
        guard let url = URL(string: "https://jsonplaceholder.typicode.com/todos") else { throw FailureReason.urlFailed }
        
        return try await withUnsafeThrowingContinuation { continuation in
            URLSession.shared.dataTask(with: url) { data, _, _ in
                guard let fetchData = data else {
                    continuation.resume(throwing: FailureReason.responseFailed)
                    return
                }
                if let listTodos = try? JSONDecoder().decode([TodosModel].self, from: fetchData) {
                    continuation.resume(returning: listTodos)
                } else {
                    continuation.resume(throwing: FailureReason.decodingFailed)
                }
            }.resume()
        }
    }
    
    func getRandomNumber() async -> Int {
        return Int.random(in: 0...999)
    }
    
    func getResults() async -> String? {
        do {
            let todoList = try await getTodos()
            let randNumber = await getRandomNumber()
            return "Todo Item Count: \(todoList.count) & Random number: \(randNumber)"
        } catch {
            print("Oops!")
        }
        return nil
    }
}

Bilmeniz gereken önemli bir noktada asenkron bir fonksiyonu sadece asenkron fonksiyon çağırabilir. URLSession içerisindeki dataTask asenkron olmadığı için ve direkt olarak bu yapıda bir throws veya data return gerçekleştirmeye çalışında derleyici hatası verir. Bu yüzden withUnsafeThrowingContinuation kullanarak bu işlemi aşabilirsiniz.

Diğer bir önemli bilgide örneğin yazdığınız asenkron fonksiyonu SwiftUI onAppear içerisinde çağırdığınızda hata ile karşılaşırsınız. Bunun nedeni asenkron olmayan gövde içerisinde fonksiyonu çağırmanızdır. Bu hatayı aşmak içinde async blok içerisinde işlemlerinizi gerçekleştirebilirsiniz.

struct ContentView: View {
    
    @ObservedObject var VM = ContentVM()
    @State var title: String = "Hello async/await"
    
    var body: some View {
        VStack {
            Text(title)
        }
        .onAppear {
            async {
                title = await VM.getResults() ?? "Oops"
            }
        }
    }
}

 

 

Kategori:Swift 5

İlk Yorumu Siz Yapın

Bir cevap yazın

E-posta hesabınız yayımlanmayacak.

Copyright © 2022 Kenan Atmaca