Ricerca…


Nozioni di base su RxSwift

FRP, o Functional Reactive Programming, ha alcuni termini di base che è necessario conoscere.

Ogni pezzo di dati può essere rappresentato come Observable , che è un flusso di dati asincrono. La potenza di FRP è rappresentata da eventi sincroni e asincroni come flussi, Observable e fornendo la stessa interfaccia per lavorare con esso.

Solitamente Observable contiene diversi (o nessuno) eventi che .Next la data - .Next Eventi successivi, e quindi può essere terminata con successo ( .Success ) o con un errore ( .Error ).

Diamo un'occhiata al seguente diagramma di marmo:

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

In questo esempio c'è un flusso di valori Int . Con il passare del tempo, tre eventi. .Next sono verificati e quindi il flusso è stato interrotto correttamente.

--X->

Il diagramma sopra mostra un caso in cui non sono stati emessi dati e. .Error evento di .Error termina l' Observable .

Prima di andare avanti, ci sono alcune risorse utili:

  1. RxSwift . Guarda gli esempi, leggi i documenti e inizia.
  2. RxSwift Slack room ha alcuni canali per la risoluzione dei problemi educativi.
  3. Gioca con RxMarbles per sapere cosa fa l'operatore e quale è il più utile nel tuo caso.
  4. Dai un'occhiata a questo esempio , esplora il codice da solo.

Creare osservabili

RxSwift offre molti modi per creare un Observable , diamo un'occhiata:

import RxSwift

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

Quindi, gli osservabili sono creati. Essi contengono solo un valore e quindi termina con successo. Tuttavia, non è successo nulla dopo che è stato creato. Perché?

Ci sono due passaggi per lavorare con Observable s: osservi qualcosa per creare uno stream e poi ti iscrivi allo stream o lo leghi a qualcosa per interagire con esso.

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

La console stamperà:

.Next(12)
.Completed()

E se mi interessa solo lavorare con i dati, che si svolgono in .Next Eventi successivi, vorrei utilizzare l'operatore subscribeNext :

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

Se voglio creare un osservabile di molti valori, utilizzo diversi operatori:

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.

E infine, forse voglio un Observable che funzioni. Ad esempio, è conveniente racchiudere un'operazione di rete in Observable<SomeResultType> . Diamo un'occhiata a fare uno può ottenere questo:

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

smaltimento

Dopo aver creato la sottoscrizione, è importante gestirne la corretta deallocazione.

I documenti ce l'hanno detto

Se una sequenza termina in un tempo limitato, non chiamare dispose o non usare addDisposableTo (disposeBag) non causerà alcuna perdita permanente di risorse. Tuttavia, tali risorse verranno utilizzate fino al completamento della sequenza, terminando la produzione di elementi o restituendo un errore.

Esistono due modi per deallocare le risorse.

  1. Utilizzo di disposeBag s e addDisposableTo operator.
  2. Usando takeUntil operatore takeUntil .

Nel primo caso si passa manualmente l'abbonamento all'oggetto DisposeBag , che cancella correttamente tutta la memoria acquisita.

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

In realtà non è necessario creare DisposeBag in ogni classe che si crea, basta dare un'occhiata al progetto RxSwift Community denominato NSObject + Rx . Utilizzando il framework il codice sopra può essere riscritto come segue:

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

Nel secondo caso, se il tempo di sottoscrizione coincide con la durata dell'oggetto self , è possibile implementare lo smaltimento utilizzando takeUntil(rx_deallocated) :

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

Attacchi

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

Usando l'operatore combineLatest ogni volta che un oggetto viene emesso da uno dei due Observables , combinare l'ultimo oggetto emesso da ciascun Observable . In questo modo combiniamo il risultato dei due UITextField creando un nuovo messaggio con il testo "Greetings, \($0)" usando l'interpolazione della stringa per legare in seguito al testo di un UILabel .

Possiamo legare i dati a qualsiasi UITableView e UICollectionView in un modo molto semplice:

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

Questo è un wrapper Rx attorno al metodo di origine dati cellForRowAtIndexPath . E anche Rx si prende cura dell'implementazione di numberOfRowsAtIndexPath , che è un metodo obbligatorio in senso tradizionale, ma non è necessario implementarlo qui, è curato.

RxCocoa e ControlEvents

RxSwift fornisce non solo i modi per controllare i dati, ma anche per rappresentare le azioni dell'utente in modo reattivo.

RxCocoa contiene tutto ciò di cui hai bisogno. Trasporta la maggior parte delle proprietà dei componenti dell'interfaccia utente in s Observable , ma non proprio. Ci sono alcuni Observable aggiornati chiamati ControlEvent (che rappresentano eventi) e ControlProperties (che rappresentano proprietà, sorpresa!). Queste cose Observable flussi Observable sotto il cofano, ma hanno anche alcune sfumature:

  • Non fallisce mai, quindi nessun errore.
  • Complete sequenza sul controllo che viene deallocato.
  • Fornisce eventi sul thread principale ( MainScheduler.instance ).

Fondamentalmente, puoi lavorare con loro come al solito:

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.

Questo è molto importante da usare: finché usi Rx, dimenticati del materiale @IBAction , tutto ciò di cui hai bisogno puoi collegarlo e configurarlo contemporaneamente. Ad esempio, il metodo viewDidLoad del tuo controller di visualizzazione è un buon candidato per descrivere come funzionano i componenti dell'interfaccia utente.

Ok, un altro esempio: supponiamo di avere un campo di testo, un pulsante e un'etichetta. Vogliamo validare il testo nel campo di testo quando si tocca il pulsante, e visualizzare i risultati in etichetta. Sì, sembra un altro compito di email di conferma, eh?

Prima di tutto, prendiamo il button.rx_tap ControlEvent:

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

Qui le parentesi vuote mostrano i tocchi dell'utente. Successivamente, prendiamo ciò che è scritto nel campo testo con withLatestFrom operatore withLatestFrom ( withLatestFrom un'occhiata qui , immaginate che il flusso superiore rappresenti i tocchi utente, quello in basso rappresenta il testo nel campo di testo).

button.rx_tap.withLatestFrom(textField.rx_text)

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

Bello, abbiamo un flusso di stringhe da convalidare, emesse solo quando abbiamo bisogno di convalidare.

Qualsiasi Observable ha operatori familiari come la map o il filter , prenderemo la map per convalidare il testo. Crea tu stesso la funzione di validateEmail mail, usa qualsiasi regex che desideri.

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) 

Fatto! Se hai bisogno di più logica personalizzata (come mostrare le visualizzazioni di errore in caso di errore, effettuare una transizione su un altro schermo in caso di successo ...), iscriviti al flusso Bool finale e scrivilo lì.



Modified text is an extract of the original Stack Overflow Documentation
Autorizzato sotto CC BY-SA 3.0
Non affiliato con Stack Overflow