Swift Language
RxSwift
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:
- RxSwift . Titta på exempel, läsa dokument och komma igång.
- RxSwift Slack room har några kanaler för utbildningsproblemlösning.
- Lek med RxMarbles för att veta vad operatören gör, och vilket är det mest användbara i ditt fall.
- 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.
- Använd
disposeBag
s ochaddDisposableTo
operatör. - 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.