ReactiveCocoa vs RxSwift: ¿pros y contras?

256

Así que ahora con swift, la gente de ReactiveCocoa lo ha reescrito en la versión 3.0 para swift

Además, ha habido otro proyecto creado llamado RxSwift .

Me pregunto si las personas podrían agregar información sobre cuáles son las diferencias en el diseño / api / filosofía de los dos marcos (por favor, en el espíritu de SO, atenerse a las cosas que son verdaderas, en lugar de opiniones sobre cuál es el "mejor")

[Nota para las modificaciones de StackOverflow: esta pregunta TIENE respuestas definitivas, la respuesta son las diferencias entre los dos marcos. Creo que también es un tema muy importante para SO]

Para comenzar, mi impresión inicial al leer sus Léame es:

  • Como alguien que está familiarizado con el "real" C # Rx de microsoft, RxSwift se ve mucho más reconocible.
  • ReactiveCococa parece haberse ido a su propio espacio ahora, introduciendo nuevas abstracciones como Signals vs SignalProducers y Lifting. Por un lado, esto parece aclarar algunas situaciones (qué es una señal de calor frente a frío), pero por otro lado, esto parece aumentar la complejidad del marco MUCHO
Orion Edwards
fuente
Su pregunta específicamente pide "opiniones". ¿Podría por favor reformular? Con mucho gusto retractaré mi voto cercano entonces.
Sulthan
2
Puede deshacerse de "agregar sus opiniones", porque las diferencias son hechos, no opiniones. Entonces le pueden gustar o no algunas características de RAC / RxSwift, pero las diferencias son claras.
bontoJR
1
jajaja, buen movimiento con respecto a la "nota a los mods"!
ming yeow
1
Cambiar el nombre de la pregunta: diferencia entre ReactiveCocoa y RxSwift. Creo que todo se convertirá en "hecho", y esta pregunta es un legado.
hqt
1
Incluso la solución comienza con "Esta es una muy buena pregunta". : |
Iulian Onofrei 01 de

Respuestas:

419

Esta es una muy buena pregunta. Comparar los dos mundos es muy difícil. Rx es un puerto de lo que son las extensiones reactivas en otros lenguajes como C #, Java o JS.

Reactive Cocoa se inspiró en la programación funcional reactiva , pero en los últimos meses también se ha inspirado en las extensiones reactivas . El resultado es un marco que comparte algunas cosas con Rx, pero tiene nombres con orígenes en FRP.

Lo primero que hay que decir es que ni RAC ni RxSwift son implementaciones de programación funcional reactiva , según la definición del concepto de Conal . Desde este punto, todo se puede reducir a cómo cada marco maneja los efectos secundarios y algunos otros componentes.

Hablemos de la comunidad y las cosas meta-tecnológicas :

  • RAC es un proyecto de 3 años de antigüedad, nacido en Objective-C, más tarde portado a Swift (con puentes) para la versión 3.0, después de abandonar por completo el trabajo en curso en Objective-C.
  • RxSwift es un proyecto de hace unos meses y parece tener un impulso en la comunidad en este momento. Una cosa que es importante para RxSwift es que está bajo la organización ReactiveX y que todas las demás implementaciones funcionan de la misma manera, aprender a lidiar con RxSwift hará que trabajar con Rx.Net, RxJava o RxJS sea una tarea simple y simplemente un asunto de sintaxis del lenguaje. Podría decir que se basa en la filosofía de aprender una vez, aplicar en todas partes .

Ahora es el momento de las cosas tecnológicas.

Entidades productoras / observadoras

RAC 3.0 tiene 2 entidades principales, Signaly SignalProducerla primera publica eventos independientemente de si un suscriptor está conectado o no, la segunda requiere startque se produzcan señales / eventos. Este diseño ha sido creado para separar el tedioso concepto de observables fríos y calientes, que ha sido fuente de confusión para muchos desarrolladores. Es por eso que las diferencias se pueden reducir a la forma en que manejan los efectos secundarios .

En RxSwift, Signaly se SignalProducertraduce en Observable, puede sonar confuso, pero estas 2 entidades son en realidad lo mismo en el mundo de Rx. Se Observabledebe crear un diseño con s en RxSwift teniendo en cuenta que si hace calor o frío, puede sonar como una complejidad innecesaria, pero una vez que haya entendido cómo funcionan (y nuevamente caliente / frío / cálido se trata solo de los efectos secundarios al suscribirse / observar ) pueden ser domesticados.

En ambos mundos, el concepto de suscripción es básicamente el mismo, hay una pequeña diferencia que RAC introdujo y es el interruptionevento cuando Signalse elimina antes de que se envíe el evento de finalización. Para recapitular, ambos tienen el siguiente tipo de eventos:

  • Next, para calcular el nuevo valor recibido
  • Error, para calcular un error y completar la secuencia, cancelando la suscripción de todos los observadores
  • Complete, para marcar la secuencia como completada cancelando la suscripción de todos los observadores

Además, RAC tiene interruptedque se envía cuando Signalse elimina a antes de completar correctamente o con un error.

Escribir manualmente

En RAC, Signal/ SignalProducerson entidades de solo lectura, no se pueden administrar desde afuera, lo mismo es para ObservableRxSwift. Para convertir a Signal/ SignalProduceren una entidad que se pueda escribir, debe usar la pipe()función para devolver un elemento controlado manualmente. En el espacio Rx, este es un tipo diferente llamado Subject.

Si el concepto de lectura / escritura no le resulta familiar, se puede hacer una buena analogía con Future/ Promise. A Futurees un marcador de posición de solo lectura, como Signal/ SignalProducery Observable, por otro lado, a Promisese puede cumplir manualmente, como para pipe()y Subject.

Programadores

Esta entidad es bastante similar en ambos mundos, los mismos conceptos, pero RAC es solo de serie, en cambio, RxSwift presenta también planificadores simultáneos.

Composición

La composición es la característica clave de la programación reactiva. La composición de flujos es la esencia de ambos marcos, en RxSwift también se les llama secuencias .

Todas las entidades observables en RxSwift son de tipo ObservableType, por lo que componimos instancias Subjecty Observablecon los mismos operadores, sin ninguna preocupación adicional.

En el espacio RAC, Signaly SignalProducerson 2 entidades diferentes y tenemos que liften SignalProducerser capaz de componer lo que se produce con las instancias de Signal. Las dos entidades tienen sus propios operadores, por lo que cuando necesita mezclar cosas, debe asegurarse de que un determinado operador esté disponible, por otro lado, se olvida de los observables frío / calor.

Sobre esta parte, Colin Eberhardt lo resumió amablemente:

Mirando la API actual, las operaciones de señal se centran principalmente en el 'próximo' evento, lo que le permite transformar valores, omitir, retrasar, combinar y observar en diferentes subprocesos. Mientras que la API del productor de señal se ocupa principalmente de los eventos del ciclo de vida de la señal (completado, error), con operaciones que incluyen entonces, flatMap, takeUntil y catch.

Extra

RAC también tiene el concepto de Actiony Property, el primero es un tipo para calcular los efectos secundarios, principalmente relacionados con la interacción del usuario, el segundo es interesante cuando se observa un valor para realizar una tarea cuando el valor ha cambiado. En el RxSwift Actionse traduce en un nuevo Observable, esto está muy bien muestra en RxCocoa, una integración de las primitivas Rx tanto para iOS y Mac. Los RAC Propertyse pueden traducir a Variable(o BehaviourSubject) en RxSwift.

Es importante comprender que Property/ Variablees la forma en que tenemos que unir el mundo imperativo con la naturaleza declarativa de la Programación Reactiva, por lo que a veces es un componente fundamental cuando se trata de bibliotecas de terceros o funcionalidades centrales del espacio iOS / Mac.

Conclusión

RAC y RxSwift son 2 bestias diferentes, la primera tiene una larga historia en el espacio Cocoa y muchos contribuyentes, la segunda es bastante joven, pero se basa en conceptos que han demostrado ser efectivos en otros lenguajes como Java, JS o .RED. La decisión sobre cuál es mejor es la preferencia. RAC afirma que la separación de calor / frío observable era necesaria y esa es la característica principal del marco, RxSwift dice que la unificación de ellos es mejor que la separación, nuevamente se trata solo de cómo se manejan / realizan los efectos secundarios.

RAC 3.0 parece haber introducido una complejidad inesperada además del objetivo principal de separar los observables frío / calor, como el concepto de interrupción, dividir los operadores entre 2 entidades e introducir un comportamiento imperativo como startcomenzar a producir señales. Para algunas personas, estas cosas pueden ser algo agradable o incluso una característica asesina, para otras pueden ser innecesarias o incluso peligrosas. Otra cosa para recordar es que RAC está tratando de mantenerse al día con las convenciones de Cocoa tanto como sea posible, por lo que si usted es un Cocoa Dev experimentado, debería sentirse más cómodo para trabajar con él en lugar de RxSwift.

RxSwift, por otro lado, vive con todas las desventajas, como los observables de frío / calor, pero también las cosas buenas de las extensiones reactivas. Pasar de RxJS, RxJava o Rx.Net a RxSwift es algo simple, todos los conceptos son los mismos, por lo que esto hace que encontrar material sea bastante interesante, tal vez el mismo problema que enfrenta ahora, alguien en RxJava lo haya resuelto y la solución se puede volver a aplicar teniendo en cuenta la plataforma.

Cuál tiene que ser elegido es definitivamente una cuestión de preferencia, desde una perspectiva objetiva es imposible saber cuál es mejor. La única forma es disparar Xcode y probar ambos y elegir el que se sienta más cómodo para trabajar. Son 2 implementaciones de conceptos similares, que intentan alcanzar el mismo objetivo: simplificar el desarrollo de software.

bontoJR
fuente
24
Esta es una gran explicación, @ junior-b! Sin embargo, también vale la pena mencionar que RAC codifica información de tipo (incluida la falta de errores gracias a NoError) en los tipos de flujo en sí: Signal<T, E: ErrorType>versus Observable<T>. Esto, así como la separación frío / calor, proporciona una mayor cantidad de información en tiempo de compilación que simplemente no tiene RxSwift.
NachoSoto
3
Hola @nachosoto, gracias por la amable palabra. Creo que la adición propuesta no encajaría tan bien en una comparación en Programación Reactiva. Definitivamente es una buena adición en el lado del RAC, pero para mí RP se trata de simplificar la programación del flujo de datos y los factores importantes son: manejo de errores, cálculo asíncrono, gestión de efectos secundarios y composición. Desde la perspectiva del desarrollador parece una buena característica, esto es para aclarar el tipo de error en el código, en realidad no está mejorando el aspecto de manejo de errores del marco, esta es, por supuesto, mi humilde opinión.
bontoJR
3
Vale la pena mencionar que a partir de ahora hay una falta de tutoriales decentes sobre RAC, sin embargo, hay algunos grandes proyectos de muestra para RxSwift que fue decisivo para mí.
Vadim Bulavin
1
ReactiveCocoa fue bueno, hasta que introdujeron funciones gratuitas, SignalProducer, genérico con Error. Aprendo RxSwift y obtengo la misma experiencia cuando trabajo con RxKotlin, RxJS
onmyway133