Zoeken…


RxSwift basisprincipes

FRP, of Functioneel Reactief Programmeren, heeft enkele basisbegrippen die u moet kennen.

Elk stuk gegevens kan worden weergegeven als Observable , wat een asynchrone gegevensstroom is. De kracht van FRP zit in de weergave van synchrone en asynchrone gebeurtenissen als streams, Observable s, en biedt dezelfde interface om ermee te werken.

Meestal Observable heeft verschillende (of geen) gebeurtenissen die de datum bevat - .Next gebeurtenissen, en dan kan worden beëindigd met succes ( .Success ) of met een fout ( .Error ).

Laten we het volgende marmeren diagram eens bekijken:

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

In dit voorbeeld is er een stroom van Int waarden. Naarmate de tijd .Next , vonden drie .Next gebeurtenissen plaats en vervolgens werd de stream met succes beëindigd.

--X->

Het bovenstaande diagram toont een geval waarin geen gegevens zijn uitgezonden en .Error gebeurtenis beëindigt de Observable .

Voordat we verder gaan, zijn er enkele nuttige bronnen:

  1. RxSwift . Bekijk voorbeelden, lees documenten en ga aan de slag.
  2. RxSwift Slack room heeft een paar kanalen voor het oplossen van onderwijsproblemen.
  3. Speel met RxMarbles om te weten wat de operator doet en welke in uw geval het handigst is.
  4. Bekijk dit voorbeeld en verken de code zelf.

Waarnemingen maken

RxSwift biedt vele manieren om een te creëren Observable , laten we eens een kijkje nemen:

import RxSwift

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

Dus, de observables zijn gemaakt. Ze hebben slechts één waarde en worden vervolgens met succes beëindigd. Toch gebeurde er niets nadat het was gemaakt. Waarom?

Er zijn twee stappen in het werken met Observable s: je observeert iets om een stream te maken en je abonneert je vervolgens op de stream of verbindt het aan iets om ermee te communiceren .

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

De console zal afdrukken:

.Next(12)
.Completed()

En als ik alleen geïnteresseerd zou zijn in het werken met gegevens, die plaatsvinden in .Next evenementen, zou ik de operator subscribeNext gebruiken:

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

Als ik een waarneembare waarde van meerdere waarden wil creëren, gebruik ik verschillende 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.

En tot slot wil ik misschien een Observable die wat werk doet. Het is bijvoorbeeld handig om een netwerkbewerking in Observable<SomeResultType> . Laten we eens kijken of iemand dit kan bereiken:

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.
}

afvoeren

Nadat het abonnement is gemaakt, is het belangrijk om de juiste deallocatie te beheren.

Dat hebben de documenten ons verteld

Als een reeks eindigt in een eindige tijd, zal het niet gebruiken van dispose of het niet gebruiken van addDisposableTo (disposeBag) geen permanente lekken veroorzaken. Deze bronnen worden echter gebruikt totdat de reeks is voltooid, hetzij door de productie van elementen te voltooien of een fout te retourneren.

Er zijn twee manieren om middelen toe te wijzen.

  1. disposeBag s en addDisposableTo operator gebruiken.
  2. takeUntil operator gebruiken.

In het eerste geval geeft u het abonnement handmatig door aan het object DisposeBag , waarmee alle opgenomen geheugen correct wordt gewist.

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

Het is niet nodig om DisposeBag s te maken in elke klasse die u maakt, kijk maar eens naar het RxSwift Community- project NSObject + Rx . Met behulp van het framework kan de bovenstaande code als volgt worden herschreven:

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

In het tweede geval de abonnementstijd samenvalt met de self object levensduur, is het mogelijk uit te voeren aanbrengen behulp takeUntil(rx_deallocated) :

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

Bindingen

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

Gebruik de operator combineLatest telkens wanneer een item wordt uitgezonden door een van de twee Observables , combineer het laatste item dat wordt uitgezonden door elke Observable . Dus op deze manier combineren we het resultaat van het creëren van een nieuw bericht door de twee UITextField met de tekst "Greetings, \($0)" met stringinterpolatie om later te binden aan de tekst van een UILabel .

We kunnen gegevens binden aan elke UITableView en UICollectionView op een zeer eenvoudige manier:

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

Dat is een Rx-wrapper rond de gegevensbronmethode cellForRowAtIndexPath . En ook Rx zorgt voor de implementatie van het numberOfRowsAtIndexPath , een vereiste methode in traditionele zin, maar u hoeft het hier niet te implementeren, het is geregeld.

RxCocoa en ControlEvents

RxSwift biedt niet alleen de manieren om uw gegevens te beheren, maar ook om acties van gebruikers op een reactieve manier weer te geven.

RxCocoa bevat alles wat u nodig heeft. Het verpakt de meeste eigenschappen van de UI-componenten in Observable s, maar niet echt. Er zijn enkele opgewaardeerde Observable s genaamd ControlEvent s (die gebeurtenissen vertegenwoordigen) en ControlProperties (die eigenschappen vertegenwoordigen, verrassing!). Deze dingen bevatten Observable streams onder de motorkap, maar hebben ook enkele nuances:

  • Het faalt nooit, dus geen fouten.
  • De reeks wordt Complete controle wordt toegewezen.
  • Het levert gebeurtenissen op de MainScheduler.instance ( MainScheduler.instance ).

Kortom, u kunt zoals gewoonlijk met hen werken:

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.

Dit is erg belangrijk om te gebruiken: zolang je Rx gebruikt, vergeet dan het @IBAction spul, alles wat je nodig hebt kun je in één keer binden en configureren. De methode viewDidLoad van uw view-controller is bijvoorbeeld een goede kandidaat om te beschrijven hoe de UI-componenten werken.

Ok, nog een voorbeeld: stel dat we een tekstveld, een knop en een label hebben. We willen de tekst in het tekstveld te valideren wanneer we op de knop, en de resultaten in de label weer te geven. Yep, lijkt me een zoveelste e-mailtaak, toch?

Allereerst pakken we de button.rx_tap ControlEvent:

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

Hier tonen lege haakjes gebruikerstappen. Vervolgens nemen we wat er in de withLatestFrom is geschreven met de operator withLatestFrom (bekijk het hier , stel je voor dat de bovenste stream staat voor gebruikerstappen, de onderste voor tekst in het tekstveld).

button.rx_tap.withLatestFrom(textField.rx_text)

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

Leuk, we hebben een reeks strings om te valideren, alleen uitgezonden wanneer we moeten valideren.

Elke Observable heeft vertrouwde operatoren zoals map of filter , we nemen map om de tekst te valideren. Maak zelf de functie validateEmail , gebruik elke gewenste regex.

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) 

Gedaan! Als je meer aangepaste logica nodig hebt (zoals het weergeven van foutweergaven in het geval van fouten, het maken van een overgang naar een ander scherm bij succes ...), abonneer je gewoon op de laatste Bool stream en schrijf het daar.



Modified text is an extract of the original Stack Overflow Documentation
Licentie onder CC BY-SA 3.0
Niet aangesloten bij Stack Overflow