Sök…


RxSwift grunder

FRP, eller Functional Reactive Programming, har några grundläggande termer som du behöver veta.

Varje data kan representeras som Observable , vilket är en asynkron dataström. FRP: s styrka representerar synkrona och asynkrona händelser som strömmar, Observable s och ger samma gränssnitt för att arbeta med det.

Vanligtvis håller Observable flera (eller inga) händelser som håller datumet - .Next händelser, och sedan kan de avslutas framgångsrikt ( .Success ) eller med ett fel ( .Error ).

Låt oss ta en titt på följande marmordiagram:

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

I det här exemplet finns det en ström av Int värden. När tiden går framåt inträffade tre .Next händelser och sedan avbröts strömmen framgångsrikt.

--X->

Diagrammet ovan visar ett fall där ingen data sändes ut och. .Error händelse avslutar det Observable .

Innan vi går vidare finns det några användbara resurser:

  1. RxSwift . Titta på exempel, läsa dokument och komma igång.
  2. RxSwift Slack room har några kanaler för utbildningsproblemlösning.
  3. Lek med RxMarbles för att veta vad operatören gör, och vilket är det mest användbara i ditt fall.
  4. Ta en titt på detta exempel , utforska koden själv.

Skapa observerbara

RxSwift erbjuder många sätt att skapa en Observable , låt oss ta en titt:

import RxSwift

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

Så, observerbara objekt skapas. De har bara ett värde och slutar sedan med framgång. Ändå händer ingenting efter det skapades. Varför?

Det finns två steg i att arbeta med Observable s: du observerar något för att skapa en ström och sedan prenumererar du på strömmen eller binder den till något för att interagera med den.

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

Konsolen kommer att skriva ut:

.Next(12)
.Completed()

Och om jag bara är intresserad av att arbeta med data, som äger rum i .Next händelser, skulle jag använda subscribeNext operator:

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

Om jag vill skapa ett observerbart av många värden använder jag olika operatörer:

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.

Och slutligen kanske jag vill ha en Observable som gör lite arbete. Till exempel är det bekvämt att linda in en nätverksoperation i Observable<SomeResultType> . Låt oss ta en titt på gör en kan uppnå detta:

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

Omhändertagande

Efter det att prenumerationen skapades är det viktigt att hantera dess korrekta omlokalisering.

Dokumenten berättade för oss det

Om en sekvens avslutas i begränsad tid, kommer inte att ringa kassera eller inte använda addDisposableTo (disposeBag) inte orsaka permanenta resursläckor. Dessa resurser kommer emellertid att användas tills sekvensen är klar, antingen genom att avsluta produktionen av element eller returnera ett fel.

Det finns två sätt att fördela resurser.

  1. Använd disposeBag s och addDisposableTo operatör.
  2. Använda takeUntil operatören.

I det första fallet DisposeBag du prenumerationen manuellt till DisposeBag objektet, vilket rensar allt taget minne korrekt.

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

Du behöver faktiskt inte skapa DisposeBag i varje klass du skapar, bara titta på RxSwift Community : s projekt med namnet NSObject + Rx . Med hjälp av ramverket kan koden ovan skrivas om enligt följande:

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

I det andra fallet, om de prenumerationstidssammanfaller med self livstid, är det möjligt att implementera anordna användning takeUntil(rx_deallocated) :

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

Bindningar

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

Använd combineLatest operatören varje gång en artikel släpps ut av någon av två Observables objekt, kombinera den senaste artikeln som släpps ut från varje Observable . Så på detta sätt kombinerar vi resultatet av de två UITextField skapande av ett nytt meddelande med texten "Greetings, \($0)" med stränginterpolering för att senare binda till texten till en UILabel .

Vi kan binda data till valfri UITableView och UICollectionView på ett mycket enkelt sätt:

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

Det är en Rx-omslag runt cellForRowAtIndexPath . Och Rx tar också hand om implementeringen av numberOfRowsAtIndexPath , som är en obligatorisk metod i traditionell mening, men du behöver inte implementera det här, det tas hand om.

RxCocoa och ControlEvents

RxSwift tillhandahåller inte bara sätten att kontrollera dina data utan också representera användaråtgärder på ett reaktivt sätt.

RxCocoa innehåller allt du behöver. Det lindar de flesta av UI-komponenternas egenskaper i Observable s, men inte riktigt. Det finns några uppgraderade Observable kallas ControlEvent (som representerar händelser) och ControlProperties (som representerar egenskaper, överraskning!). Dessa saker håller Observable strömmar under huven, men har också några nyanser:

  • Det misslyckas aldrig, så inga fel.
  • Det kommer att Complete sekvensen på kontrollen som omlokaliseras.
  • Den levererar händelser på MainScheduler.instance ( MainScheduler.instance ).

I princip kan du arbeta med dem som vanligt:

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.

Detta är mycket viktigt att använda: så länge du använder Rx, glöm allt från @IBAction saker, allt du behöver kan du binda och konfigurera på en gång. Till exempel är viewDidLoad metoden för din visningskontroller en bra kandidat för att beskriva hur UI-komponenterna fungerar.

Ok, ett annat exempel: antar att vi har ett textfält, en knapp och en etikett. Vi vill validera text i textfältet när vi trycker på knappen och visar resultaten i etiketten. Jepp, verkar som en annan validerings-e-postuppgift, va?

Först av allt tar vi button.rx_tap ControlEvent:

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

Här visar tomma parenteser användarens kranar. Därefter tar vi det som är skrivet i textfältet med operatören withLatestFrom (titta på det här , föreställ dig att övre strömmen representerar användarkranar, den nedre representerar text i textfältet).

button.rx_tap.withLatestFrom(textField.rx_text)

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

Trevligt, vi har en ström av strängar att validera, släpps endast när vi behöver validera.

Alla Observable har sådana kända operatörer som map eller filter , vi tar en map att validera texten. Skapa validateEmail funktionen själv, använd vilken regex du vill ha.

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) 

Gjort! Om du behöver mer anpassad logik (som att visa felvyer vid fel, göra en övergång till en annan skärm för framgång ...), prenumerera bara på den sista Bool strömmen och skriv den där.



Modified text is an extract of the original Stack Overflow Documentation
Licensierat under CC BY-SA 3.0
Inte anslutet till Stack Overflow