Suche…


RxSwift-Grundlagen

FRP oder Functional Reactive Programming hat einige grundlegende Begriffe, die Sie kennen müssen.

Jedes Datenelement kann als Observable , bei dem es sich um einen asynchronen Datenstrom handelt. Die Leistungsfähigkeit von FRP besteht darin, synchrone und asynchrone Ereignisse als Streams, Observable s, darzustellen und dieselbe Schnittstelle für die Arbeit damit zu bieten.

Normalerweise enthält Observable mehrere (oder keine) Ereignisse, die das Datum enthalten - .Next Ereignisse. Anschließend können sie erfolgreich ( .Success ) oder mit einem Fehler ( .Error ) beendet werden.

Schauen wir uns das folgende Marmordiagramm an:

--(1)--(2)--(3)|-->

In diesem Beispiel gibt es einen Strom von Int Werten. Mit der Zeit traten drei .Next Ereignisse auf, und der Stream wurde erfolgreich beendet.

--X->

Das obige Diagramm zeigt einen Fall, in dem keine Daten .Error und das .Error Ereignis das Observable beendet.

Bevor wir fortfahren, gibt es einige nützliche Ressourcen:

  1. RxSwift . Sehen Sie sich Beispiele an, lesen Sie Dokumente und machen Sie sich an die Arbeit.
  2. Im RxSwift Slack-Raum gibt es einige Kanäle zur Lösung von Problemen mit dem Bildungswesen.
  3. Spielen Sie mit RxMarbles herum, um zu erfahren, was der Operator tut und welcher in Ihrem Fall am nützlichsten ist.
  4. Schauen Sie sich dieses Beispiel an , erkunden Sie den Code selbst.

Observable erstellen

RxSwift bietet viele Möglichkeiten, ein Observable zu erstellen, werfen wir einen Blick darauf:

import RxSwift

let intObservale = Observable.just(123) // Observable<Int>
let stringObservale = Observable.just("RxSwift") // Observable<String>
let doubleObservale = Observable.just(3.14) // Observable<Double>

So werden die Observablen erstellt. Sie haben nur einen Wert und enden dann mit Erfolg. Trotzdem passiert nichts, nachdem es erstellt wurde. Warum?

Es gibt zwei Schritte bei der Arbeit mit Observable s: Sie beobachten etwas, um einen Stream zu erstellen, und dann abonnieren Sie den Stream oder binden ihn an etwas, um damit zu interagieren .

Observable.just(12).subscribe {
    print($0)
}

Die Konsole druckt:

.Next(12)
.Completed()

Und wenn ich nur mit Daten arbeiten möchte, die in .Next Ereignissen stattfinden, würde ich den subscribeNext Operator verwenden:

Observable.just(12).subscribeNext {
    print($0) // prints "12" now
}

Wenn ich ein Observable mit vielen Werten erstellen möchte, verwende ich verschiedene Operatoren:

Observable.of(1,2,3,4,5).subscribeNext {
    print($0)
}
// 1
// 2
// 3
// 4
// 5

// I can represent existing data types as Observables also:
[1,2,3,4,5].asObservable().subscribeNext { 
    print($0) 
}
// result is the same as before.

Und schließlich möchte ich vielleicht ein Observable , das etwas Arbeit leistet. Zum Beispiel ist es praktisch, einen Netzwerkvorgang in Observable<SomeResultType> . Werfen wir einen Blick darauf, wie man das erreichen kann:

Observable.create { observer in    // create an Observable ...
    MyNetworkService.doSomeWorkWithCompletion { (result, error) in
        if let e = error {
            observer.onError(e)    // ..that either holds an error
        } else {
            observer.onNext(result) // ..or emits the data
            observer.onCompleted()  // ..and terminates successfully.
        }
    }
    return NopDisposable.instance // here you can manually free any resources
                                //in case if this observable is being disposed.
}

Entsorgen

Nachdem das Abonnement erstellt wurde, ist es wichtig, seine korrekte Freigabe zu verwalten.

Die Dokumente haben uns das gesagt

Wenn eine Sequenz in endlicher Zeit beendet wird, verursacht das Aufrufen von dispose oder das Verwenden von addDisposableTo (disposeBag) keine permanenten Ressourcenlecks. Diese Ressourcen werden jedoch bis zum Abschluss der Sequenz verwendet, entweder durch Abschluss der Produktion von Elementen oder durch Rückgabe eines Fehlers.

Es gibt zwei Möglichkeiten, Ressourcen freizugeben.

  1. Verwenden disposeBag addDisposableTo Operators s und addDisposableTo .
  2. takeUntil Operator verwenden.

Im ersten Fall übergeben Sie das Abonnement manuell an das DisposeBag Objekt, das den DisposeBag Speicherplatz ordnungsgemäß löscht.

let bag = DisposeBag()
Observable.just(1).subscribeNext { 
    print($0)
}.addDisposableTo(bag)

Sie müssen nicht in jeder von Ihnen erstellten Klasse DisposeBag s erstellen. DisposeBag Sie sich einfach das RxSwift Community -Projekt mit dem Namen NSObject + Rx an . Mit Hilfe des Frameworks kann der Code wie folgt umgeschrieben werden:

Observable.just(1).subscribeNext { 
    print($0)
}.addDisposableTo(rx_disposeBag)

Im zweiten Fall, wenn die Abonnementzeit mit der Lebensdauer des self übereinstimmt, ist es möglich, die Entsorgung mit takeUntil(rx_deallocated) zu implementieren:

let _ = sequence
    .takeUntil(rx_deallocated)
    .subscribe {
        print($0)
    }

Bindungen

Observable.combineLatest(firstName.rx_text, lastName.rx_text) { $0 + " " + $1 }
.map { "Greetings, \($0)" }
.bindTo(greetingLabel.rx_text)

Verwenden Sie den combineLatest Operator jedes Mal, wenn ein Objekt von einem der beiden Observables combineLatest wird, das letzte Element, das von jedem Observable . Auf diese Weise kombinieren wir auf diese Weise das Ergebnis der Erstellung einer neuen Nachricht durch den UITextField mit dem Text "Greetings, \($0)" Verwendung der String-Interpolation, um später an den Text eines UILabel zu binden.

Wir können Daten auf einfache Weise an jede UITableView und UICollectionView binden:

viewModel
.rows
.bindTo(resultsTableView.rx_itemsWithCellIdentifier("WikipediaSearchCell", cellType: WikipediaSearchCell.self)) { (_, viewModel, cell) in
    cell.title = viewModel.title
    cell.url = viewModel.url
}
.addDisposableTo(disposeBag)

cellForRowAtIndexPath ist ein Rx-Wrapper für die Datenquellenmethode cellForRowAtIndexPath . Und Rx kümmert sich auch um die Implementierung von numberOfRowsAtIndexPath , einer Methode, die im traditionellen Sinne erforderlich ist, aber Sie müssen sie hier nicht implementieren, sie wird numberOfRowsAtIndexPath .

RxCocoa und ControlEvents

RxSwift bietet nicht nur die Möglichkeit, Ihre Daten zu kontrollieren, sondern auch Benutzeraktionen auf reaktive Weise darzustellen.

RxCocoa enthält alles was Sie brauchen. Es packt die meisten Eigenschaften der UI-Komponenten in Observable s ein, aber nicht wirklich. Es gibt einige aktualisierte Observable ControlEvent namens ControlEvent s (die Ereignisse darstellen) und ControlProperties (die Eigenschaften darstellen, Überraschung!). Diese Dinge halten Observable Ströme unter der Haube, sondern haben auch einige Nuancen:

  • Es versagt nie, also keine Fehler.
  • Es wird Complete Sie Sequenz auf Steuerausgeplant werden.
  • Es liefert Ereignisse im Hauptthread ( MainScheduler.instance ).

Grundsätzlich können Sie wie gewohnt mit ihnen arbeiten:

button.rx_tap.subscribeNext { _ in   // control event
    print("User tapped the button!")
}.addDisposableTo(bag)

textField.rx_text.subscribeNext { text in // control property
    print("The textfield contains: \(text)")
}.addDisposableTo(bag)
// notice that ControlProperty generates .Next event on subscription
// In this case, the log will display 
// "The textfield contains: "
// at the very start of the app.

Dies ist sehr wichtig für die Verwendung: @IBAction Sie Rx verwenden, vergessen Sie den @IBAction Zeugs. Alles, was Sie brauchen, können Sie sofort binden und konfigurieren. Die viewDidLoad Methode Ihres View-Controllers ist beispielsweise ein guter Kandidat, um die Funktionsweise der UI-Komponenten zu beschreiben.

Ok, ein anderes Beispiel: Nehmen wir an, wir haben ein Textfeld, eine Schaltfläche und eine Bezeichnung. Wir möchten Text im Textfeld überprüfen, wenn wir auf die Schaltfläche tippen , und die Ergebnisse in der Beschriftung anzeigen . Ja, es scheint eine weitere Validate-E-Mail-Aufgabe zu sein, oder?

Zuerst greifen wir das button.rx_tap ControlEvent:

----()-----------------------()----->

Hier zeigen leere Klammern die Benutzeranschläge an. Als Nächstes nehmen wir das, was in textField geschrieben ist, mit dem withLatestFrom Operator (sehen Sie sich das hier an , stellen Sie sich vor , dass der obere Stream Benutzer-Taps darstellt, der untere Text den Text im Textfeld).

button.rx_tap.withLatestFrom(textField.rx_text)

----("")--------------------("123")--->
//  ^ tap   ^ i wrote 123    ^ tap

Schön, wir haben einen Strom von Strings zu validieren, der nur dann ausgegeben wird, wenn wir validieren müssen.

Jedes Observable verfügt über vertraute Operatoren wie map oder filter . Wir nehmen map zur Validierung des Texts. Erstellen Sie die validateEmail Funktion selbst und verwenden Sie einen beliebigen regulären Ausdruck.

button.rx_tap                                // ControlEvent<Void>
        .withLatestFrom(textField.rx_text)   // Observable<String>
        .map(validateEmail)                  // Observable<Bool>
        .map { (isCorrect) in
            return isCorrect ? "Email is correct" : "Input the correct one, please"
        }                                    // Observable<String>
        .bindTo(label.rx_text)              
        .addDisposableTo(bag) 

Erledigt! Wenn Sie mehr benutzerdefinierte Logik benötigen (z. B. Fehleransichten anzeigen, bei Erfolg zu einem anderen Bildschirm wechseln ...), abonnieren Sie einfach den endgültigen Bool Stream und schreiben Sie ihn dort.



Modified text is an extract of the original Stack Overflow Documentation
Lizenziert unter CC BY-SA 3.0
Nicht angeschlossen an Stack Overflow