Buscar..


Conceptos básicos de RxSwift

FRP, o Programación reactiva funcional, tiene algunos términos básicos que debe conocer.

Cada dato puede representarse como Observable , que es un flujo de datos asíncrono. El poder de FRP está en representación de eventos síncronos y asíncronos como flujos, Observable s, y proporciona la misma interfaz para trabajar con él.

Por lo general, Observable tiene varios eventos (o ninguno) que contienen la fecha: eventos .Next , y luego puede terminarse con éxito ( .Success ) o con un error ( .Error ).

Echemos un vistazo al siguiente diagrama de mármol:

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

En este ejemplo hay un flujo de valores Int . A medida que el tiempo avanza, se .Next tres eventos .Next y, a continuación, la secuencia terminó correctamente.

--X->

El diagrama anterior muestra un caso en el que no se emitieron datos y el evento .Error finaliza el Observable .

Antes de continuar, hay algunos recursos útiles:

  1. RxSwift . Mira ejemplos, lee documentos y comienza.
  2. RxSwift Slack room tiene algunos canales para resolver problemas de educación.
  3. Juega con RxMarbles para saber qué hace el operador y cuál es el más útil en tu caso.
  4. Echa un vistazo a este ejemplo , explora el código por ti mismo.

Creando observables

RxSwift ofrece muchas formas de crear un Observable , echemos un vistazo:

import RxSwift

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

Así, se crean los observables. Tienen un solo valor y luego terminan con éxito. Sin embargo, nada sucedió después de que fue creado. ¿Por qué?

Hay dos pasos para trabajar con Observable s: observas algo para crear una secuencia y luego te suscribes a la secuencia o lo vinculas a algo para interactuar con ella.

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

La consola imprimirá:

.Next(12)
.Completed()

Y si solo me interesa trabajar con datos, que tienen lugar en eventos .Next , usaría el operador subscribeNext :

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

Si quiero crear un observable de muchos valores, uso diferentes operadores:

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.

Y finalmente, tal vez quiero un Observable que haga algo de trabajo. Por ejemplo, es conveniente envolver una operación de red en Observable<SomeResultType> . Echemos un vistazo a uno puede lograr esto:

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

Desechando

Una vez que se creó la suscripción, es importante administrar su desasignación correcta.

Los docs nos dijeron que

Si una secuencia termina en un tiempo finito, no llamar a dispose o no usar addDisposableTo (disposeBag) no causará ninguna fuga permanente de recursos. Sin embargo, esos recursos se utilizarán hasta que la secuencia se complete, ya sea terminando la producción de elementos o devolviendo un error.

Hay dos formas de desasignar recursos.

  1. Usando disposeBag sy el operador addDisposableTo .
  2. Utilizando el operador takeUntil .

En el primer caso, usted pasa manualmente la suscripción al objeto DisposeBag , que borra correctamente toda la memoria tomada.

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

En realidad, no es necesario crear DisposeBag s en cada clase que cree, solo eche un vistazo al proyecto de la Comunidad RxSwift llamado NSObject + Rx . Usando el marco, el código anterior puede reescribirse como sigue:

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

En el segundo caso, si el tiempo de suscripción coincide con el self duración del objeto, es posible implementar la eliminación usando takeUntil(rx_deallocated) :

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

Fijaciones

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

Usando el operador combineLatest cada vez que un elemento sea emitido por cualquiera de los dos Observables , combine el último elemento emitido por cada Observable . Entonces, de esta manera, combinamos el resultado de los dos UITextField 's creando un nuevo mensaje con el texto "Greetings, \($0)" utilizando la interpolación de cadenas para enlazar más tarde al texto de un UILabel .

Podemos enlazar datos a cualquier UITableView y UICollectionView de una manera muy fácil:

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

Eso es un envoltorio Rx alrededor del método de fuente de datos cellForRowAtIndexPath . Y también Rx se encarga de la implementación de numberOfRowsAtIndexPath , que es un método requerido en un sentido tradicional, pero no tiene que implementarlo aquí, se cuida.

RxCocoa y ControlEvents

RxSwift proporciona no solo las formas de controlar sus datos, sino que también representa las acciones de los usuarios de manera reactiva.

RxCocoa contiene todo lo que necesitas. Envuelve la mayoría de las propiedades de los componentes de la interfaz de usuario en Observable s, pero no realmente. Hay algunos Observable actualizados llamados ControlEvent s (que representan eventos) y ControlProperties (que representan propiedades, ¡sorpresa!). Estas cosas contienen corrientes Observable bajo el capó, pero también tienen algunos matices:

  • Nunca falla, así que no hay errores.
  • Se Complete secuencia de control desasignada.
  • Ofrece eventos en el hilo principal ( MainScheduler.instance ).

Básicamente, puedes trabajar con ellos como de costumbre:

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.

Esto es muy importante de usar: siempre que uses Rx, olvídate de las cosas de @IBAction , todo lo que necesites se puede vincular y configurar a la vez. Por ejemplo, el método viewDidLoad de su controlador de vista es un buen candidato para describir cómo funcionan los componentes de la interfaz de usuario.

Ok, otro ejemplo: supongamos que tenemos un campo de texto, un botón y una etiqueta. Queremos validar el texto en el campo de texto cuando nos toque el botón y mostrar los resultados en la etiqueta. Sí, parece otra tarea de validar correo electrónico, ¿eh?

En primer lugar, tomamos el button.rx_tap ControlEvent:

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

Aquí los paréntesis vacíos muestran los grifos del usuario. A continuación, tomamos lo que está escrito en el campo de texto con el operador withLatestFrom ( withLatestFrom un vistazo aquí , imagine que la secuencia superior representa los toques del usuario, la parte inferior representa el texto en el campo de texto).

button.rx_tap.withLatestFrom(textField.rx_text)

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

Bien, tenemos una secuencia de cadenas para validar, emitidas solo cuando necesitamos validar.

Cualquier Observable tiene operadores tan familiares como map o filter , tomaremos el map para validar el texto. Cree la función validateEmail usted mismo, use cualquier expresión regular que desee.

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) 

¡Hecho! Si necesita más lógica personalizada (como mostrar vistas de error en caso de error, hacer una transición a otra pantalla en caso de éxito ...), simplemente suscríbase a la secuencia final de Bool y escríbala allí.



Modified text is an extract of the original Stack Overflow Documentation
Licenciado bajo CC BY-SA 3.0
No afiliado a Stack Overflow