İçeriğe geç

URLSession Publisher kullanımı

Merhabalar bu yazımda Combine ile iOS uygulamalarınızda servis isteklerini nasıl yönetip kullanabileceğinizi paylaşacağım.

Bu işlem için URLSession üzerinden publish işlemi yapacağız. Bu işlemler içerisinde error handle, decode ve gerekli tüm işlemlerimizi gerçekleştirebiliriz. Kullanım olarak daha öncesinde Rx kullananlar için yabancı gelmeyecektir.

Aşağıda yazdığım basit bir servis isteği ve ardından gerçekleşen decode örneğini inceleyebilirsiniz.

import UIKit
import Combine

struct Httpbin: Decodable {
    var origin:String!
    var url:String!
}

enum ServiceError: Error {
    case bad
    case apiError(txt:String)
}

extension ServiceError: LocalizedError {
    var errorDescription: String? {
        switch self {
        case .bad: return "Ooops request error!"
        case .apiError(let str): return str
        }
    }
}

class ViewController: UIViewController {
  
    var requestSub:AnyCancellable?
    
    override func viewDidLoad() {
        super.viewDidLoad()
    }
    
    override func touchesBegan(_ touches: Set<UITouch>, with event: UIEvent?) {
        requestSub = serviceRequest()
        .sink(receiveCompletion: { (completion) in
                switch(completion) {
                case .finished: print("Finish")
                case .failure(let err): print(err.localizedDescription)
                }
            }) { (value) in
                print("Origin -> \(value.origin ?? "")")
        }
    }
    
    func serviceRequest() -> AnyPublisher<Httpbin, Error> {
        return URLSession.shared.dataTaskPublisher(for: URL(string: "https://httpbin.org/get")!)
        .handleEvents(receiveSubscription: { (_) in
            print("START")
        }, receiveCompletion: { (_) in
            print("Completed")
        }, receiveCancel: {
            print("Cancel")
        })
        .tryMap { data, response in
            guard let httpResponse = response as? HTTPURLResponse, 200..<300 ~= httpResponse.statusCode else {
                throw ServiceError.bad
            }
            return data
        }
        .decode(type: Httpbin.self, decoder: JSONDecoder())
        .mapError { err in
            if let error = err as? ServiceError {
                return error
            } else {
                return ServiceError.apiError(txt: "Problem occurred!")
            }
        }
        .subscribe(on: RunLoop.main)
        .eraseToAnyPublisher()
    }
}
START
Origin -> 195.214.144.202, 195.214.144.202
Completed
Finish

URLSession üzerinden dataTaskPublisher kullanarak publisher yazmaya başlıyoruz ve ardından dilerseniz durum eventlerini .handleEvents içerisindeki bloklara yazabilirsiniz. (loading animasyon işlemleri vs) daha sonrasında error handle edecekseniz tryMap ile blok içerisinde durumları yazıyorsunuz. Sonrasında aynı blok içerisinden dönen veriyi .decode ile hızlı bir şekilde uygun Decodable yapımıza decode edebiliyoruz. Seneryoda karşılaşıcak her hangi bir hata durumunda tetiklenmesi için .mapError kullanabilir ve uygun olan hatayı döndürebilirsiniz.

Thread handling operatorlerinden receive, subscribe ile zincirleri bağlayabiliyoruz. Aralarındaki kullanım farkı eğer UI ile bağlantılı bir işlem yapacaksanız .receive kullanmanız gerekir. Sonrasında .eraseToAnyPublisher ile uygun return tipimize göre son halini elde edip artık subscribe olabiliriz. Daha sonrasında .sink ile bağlanıp gerekli sonuçlara ulaşıyoruz.

Kategori:Combine

İlk Yorumu Siz Yapın

Bir cevap yazın

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

Copyright © 2022 Kenan Atmaca