URLSession, Web-API-Aufrufe Reaktiver Weg (RxSwift, RxCocoa)

In diesem Beitrag wird erläutert, wie Sie URLSession für Ihre Web-API-Aufrufe auf reaktive Weise verwenden. Es gibt viele Möglichkeiten, wie Sie asynchronen Code schreiben können, z. B. die Verwendung von NotificaitionCenter, Delegatmuster, Grand Central Dispatch, Closures, und ein Teil Ihres Codes ist bereits asynchron wie UI-Komponenten.

Alle diese Möglichkeiten sind gut für einige Anwendungsfälle, die Ihre Anwendung möglicherweise benötigt, und die Wahl zwischen ihnen hängt von Ihrem typischen Anwendungsfall ab.
Heute werden wir eine API-Klasse erstellen, die Ihre Web-API-Aufrufe auf reaktive Weise und an einem Ort behandelt.

1. RxSwift-Einführung

Grundlage der reaktiven Art der Programmierung sind Beobachtbare und Beobachter. Beobachtbare stellen eine Klasse dar, die in einem bestimmten Zeitraum asynchron eine Folge von Ereignissen erzeugen kann, die einige Daten enthalten können. Dies bedeutet, dass Beobachter Observable-Klassen für von Observable ausgegebene Werte abonnieren können, damit sie in Echtzeit auf diese Ereignisse reagieren können.
Ein Observable kann diese drei Arten von Ereignissen aussenden (und Beobachter können diese empfangen):
Nächstes Ereignis: Dieses Ereignis trägt den neuesten Datenwert.
Abgeschlossenes Ereignis: Dieses Ereignis beendet die Ereignissequenz erfolgreich, und Observable gibt keine neuen Ereignisse aus.
Fehlerereignis: Dieses Ereignis wird mit einem Fehler beendet und Observable gibt keine neuen Ereignisse aus.

Wenn wir also wollen, dass unser Observable ein Ereignis mit Werten ausgibt, die wir brauchen, müssen wir unser Observable abonnieren.
Eine weitere wichtige Sache, die wir tun müssen, ist, das Beobachterabonnement für Observable zu kündigen. Dies geschieht automatisch mit abgeschlossenen oder Fehlerereignissen, aber wir können dies manuell tun, indem wir dispose() für unser Abonnement aufrufen. Dafür haben wir den DisposeBag-Typ, der Einwegartikel enthält und dispose() für jeden aufruft, wenn der Entsorgungsbeutel freigegeben werden soll.

2. Erstellen Sie ein Modell, das Daten trägt

Um unsere Datentypen für die Kompatibilität mit externen Repräsentationen wie JSON kodierbar und dekodierbar zu machen, definiert die Swift-Standardbibliothek einen standardisierten Ansatz für die Datenkodierung und -dekodierung. Das bedeutet, dass unser Modell den codierbaren Protokollen entsprechen muss. Das Hinzufügen von Codable zur Vererbungsliste für unser Modell löst eine automatische Konformität aus, die alle Protokollanforderungen von Encodable und Decodable erfüllt.

import Foundation
//MARK: PostModel
public struct PostModel: Codable {
  private var id: Int
  private var userId: Int 
  private var title: String
  private var body: String
  init(id: Int, userId: Int, title: String, body: String) {
     self.id = id
     self.userId = userId
     self.title = title
     self.body = body
  }
  func getId() -> Int {
    return self.id
  }
  func getUserId() -> Int {
    return self.userId
  }
  func getTitle() -> String {
    return self.title
  }
  func getBody() -> String {
    return self.body
  }
}

3. Erstellen Sie eine Anforderungsklasse

Lassen Sie uns nun unsere Request-Klasse erstellen, die unser Observable erstellt und unsere Netzwerklogik mithilfe von URLSession implementiert. Hier verwenden wir den create-Operator. Dieser Operator nimmt einen einzigen Parameter namens “subscribe”. Dieser Parameter ist ein Escape-Closure, der einen AnyObserver akzeptiert und ein Disposable zurückgibt.


import Foundation
import RxSwift
import RxCocoa
//MARK: RequestObservable class
public class RequestObservable {
  private lazy var jsonDecoder = JSONDecoder()
  private var urlSession: URLSession
  public init(config:URLSessionConfiguration) {
      urlSession = URLSession(configuration:  
                URLSessionConfiguration.default)
  }
//MARK: function for URLSession takes
  public func callAPI<ItemModel: Decodable>(request: URLRequest)
    -> Observable<ItemModel> {
  //MARK: creating our observable
  return Observable.create { observer in
  //MARK: create URLSession dataTask
  let task = self.urlSession.dataTask(with: request) { (data,
                response, error) in
  if let httpResponse = response as? HTTPURLResponse{
  let statusCode = httpResponse.statusCode
  do {
    let _data = data ?? Data()
    if (200...399).contains(statusCode) {
      let objs = try self.jsonDecoder.decode(ItemModel.self, from:  
                          _data)
      //MARK: observer onNext event
      observer.onNext(objs)
    }
    else {
      observer.onError(error!)
    }
  } catch {
      //MARK: observer onNext event
      observer.onError(error)
     }
   }
     //MARK: observer onCompleted event
     observer.onCompleted()
   }
     task.resume()
     //MARK: return our disposable
     return Disposables.create {
       task.cancel()
     }
   }
  }
}

4. Erstellen Sie ein WebAPI-Singleton

Diese Klasse ist für die Erstellung von HTTP-Anforderungen an unsere Web-API verantwortlich. Hier können wir abhängig von unseren Web-API-Methoden mehrere Arten von Anfragen hinzufügen. Hier werden wir nur zwei davon hinzufügen, einen get und einen post. Unsere Methoden geben natürlich beobachtbare zurück, die wir später in unseren Controller eintragen werden.

import Foundation
import RxCocoa
import RxSwift
//MARK: extension for converting out RecipeModel to jsonObject
fileprivate extension Encodable {
  var dictionaryValue:[String: Any?]? {
      guard let data = try? JSONEncoder().encode(self),
      let dictionary = try? JSONSerialization.jsonObject(with: data,    
        options: .allowFragments) as? [String: Any] else {
      return nil
    }
    return dictionary
  }
}
class APIClient {
  static var shared = APIClient()
  lazy var requestObservable = RequestObservable(config: .default)
  func getRecipes() throws -> Observable<[PostModel]> {
    var request = URLRequest(url:    
          URL(string:"
    request.httpMethod = "GET"
    request.addValue("application/json", forHTTPHeaderField: 
              "Content-Type")
    return requestObservable.callAPI(request: request)
  }
  
  func sendPost(recipeModel: PostModel) -> Observable<PostModel> {
     var request = URLRequest(url:  
          URL(string:"
     request.httpMethod = "POST"
     request.addValue("application/json", forHTTPHeaderField: 
      "Content-Type")
     let payloadData = try? JSONSerialization.data(withJSONObject:   
           recipeModel.dictionaryValue!, options: [])
     request.httpBody = payloadData
     return requestObservable.callAPI(request: request)
   }
}

5. Verwenden Sie WebAPI-Singleton im Viewcontroller##

Und schließlich verwenden wir unser Singleton mit Observable in unserem Controller. Hier abonnieren wir unser Observable und warten auf emittierte Events.

import UIKit
import RxSwift
import RxCocoa
class ViewController: UIViewController {
  var posts: [PostModel] = []
  let disposeBag = DisposeBag()
  override func viewDidLoad() {
    super.viewDidLoad()
    
    let client = APIClient.shared
    do{
      try client.getRecipes().subscribe(
        onNext: { result in
           self.posts = result
           //MARK: display in UITableView
        },
        onError: { error in
           print(error.localizedDescription)
        },
        onCompleted: {
           print("Completed event.")
        }).disposed(by: disposeBag)
      }
      catch{
    }
  }
}

Vielen Dank, dass Sie bis hierhin gelesen haben. Bitte klatschen Sie in die Hände und besuchen Sie meine Website:

Code ist auf github verfügbar:

Kontaktieren Sie mich unter:

begic_kenan@hotmail.com
info@redundantcoding.com
www.linkedin.com/in/kenan-begić-05733361

Similar Posts

Leave a Reply

Your email address will not be published. Required fields are marked *