ReactiveCocoa vs RxSwift - Vor- und Nachteile?

256

Jetzt mit Swift haben die ReactiveCocoa- Leute es in Version 3.0 für Swift umgeschrieben

Außerdem wurde ein weiteres Projekt namens RxSwift gestartet .

Ich frage mich, ob die Leute Informationen über die Unterschiede in Design / API / Philosophie der beiden Frameworks hinzufügen könnten (bitte halten Sie sich im Sinne von SO an Dinge, die wahr sind, und nicht an Meinungen, die "am besten" sind).

[Hinweis für StackOverflow-Mods: Diese Frage hat endgültige Antworten, die Antwort sind die Unterschiede zwischen den beiden Frameworks. Ich denke, es ist auch sehr thematisch für SO]

Mein erster Eindruck beim Lesen der ReadMes ist:

  • Als jemand, der mit dem "echten" C # Rx von Microsoft vertraut ist, sieht RxSwift viel besser erkennbar aus.
  • ReactiveCococa scheint jetzt in seinen eigenen Raum gegangen zu sein und neue Abstraktionen wie Signale gegen Signalproduzenten und Heben eingeführt zu haben. Einerseits scheint dies einige Situationen zu klären (was ist ein Hot vs Cold-Signal), andererseits scheint dies die Komplexität des Frameworks um ein Vielfaches zu erhöhen
Orion Edwards
quelle
Ihre Frage fragt speziell nach "Meinungen". Könnten Sie bitte umformulieren? Ich werde dann gerne meine enge Abstimmung zurückziehen.
Sulthan
2
Sie können "ihre Meinungen hinzufügen" loswerden, weil die Unterschiede Fakten sind, keine Meinungen. Dann können Sie einige Funktionen von RAC / RxSwift mögen oder nicht mögen, aber die Unterschiede sind kristallklar.
bontoJR
1
hahaha, guter Zug bezüglich der "Note to Mods"!
Ming Yeow
1
Frage umbenennen: Unterschied zwischen ReactiveCocoa und RxSwift. Ich denke, alles wird "Tatsache", und diese Frage ist Vermächtnis.
hqt
1
Sogar die Lösung beginnt mit "Dies ist eine sehr gute Frage." : |
Iulian Onofrei

Antworten:

419

Das ist eine sehr gute Frage. Der Vergleich der beiden Welten ist sehr schwierig. Rx ist eine Portierung von Reactive Extensions in anderen Sprachen wie C #, Java oder JS.

Reactive Cocoa wurde von Functional Reactive Programming inspiriert , wurde aber in den letzten Monaten auch von Reactive Extensions inspiriert . Das Ergebnis ist ein Framework, das einige Dinge mit Rx teilt, aber Namen mit Ursprung in FRP hat.

Das erste, was zu sagen ist, ist, dass weder RAC noch RxSwift gemäß Conals Definition des Konzepts Implementierungen der funktionalen reaktiven Programmierung sind . Ab diesem Punkt kann alles darauf reduziert werden, wie jedes Framework mit Nebenwirkungen und einigen anderen Komponenten umgeht.

Lassen Sie uns über die Community und Meta-Tech- Dinge sprechen :

  • RAC ist ein 3 Jahre altes Projekt, das in Objective-C geboren wurde und später für die Version 3.0 nach Swift (mit Bridges) portiert wurde, nachdem die laufenden Arbeiten an Objective-C vollständig eingestellt wurden.
  • RxSwift ist ein paar Monate altes Projekt und scheint derzeit eine Dynamik in der Community zu haben. Eine Sache, die für RxSwift wichtig ist, ist, dass sie unter der ReactiveX- Organisation steht und dass alle anderen Implementierungen auf die gleiche Weise funktionieren. Wenn Sie lernen, wie Sie mit RxSwift umgehen, wird die Arbeit mit Rx.Net, RxJava oder RxJS zu einer einfachen Aufgabe und nur zu einer Angelegenheit der Sprachsyntax. Ich könnte sagen, das basiert auf der Philosophie einmal lernen, überall anwenden .

Jetzt ist es Zeit für das technische Zeug.

Entitäten produzieren / beobachten

RAC 3.0 hat zwei Hauptentitäten, Signalund SignalProducerdie erste veröffentlicht Ereignisse, unabhängig davon, ob ein Teilnehmer angeschlossen ist oder nicht, die zweite erfordert start, dass tatsächlich Signale / Ereignisse erzeugt werden. Dieses Design wurde entwickelt, um das langwierige Konzept von heißen und kalten Observablen zu trennen, das für viele Entwickler Verwirrung stiftete. Aus diesem Grund können die Unterschiede auf die Art und Weise reduziert werden, wie sie mit Nebenwirkungen umgehen .

In RxSwift Signalund SignalProducerübersetzt Observablekönnte es verwirrend klingen, aber diese beiden Entitäten sind in der Rx-Welt tatsächlich dasselbe. Ein Design mit Observables in RxSwift muss erstellt werden, wenn berücksichtigt wird, ob es heiß oder kalt ist. Es kann sich als unnötige Komplexität anhören. Wenn Sie jedoch erst einmal verstanden haben, wie sie funktionieren (und wieder ist heiß / kalt / warm, sind nur die Nebenwirkungen beim Abonnieren / Beobachten ) Sie können gezähmt werden.

In beiden Welten ist das Abonnementkonzept grundsätzlich dasselbe. Es gibt einen kleinen Unterschied, den RAC eingeführt hat, und es ist das interruptionEreignis, wenn a Signalentsorgt wird, bevor das Abschlussereignis gesendet wurde. Um beide zusammenzufassen, haben die folgenden Arten von Ereignissen:

  • Next, um den neu empfangenen Wert zu berechnen
  • Error, um einen Fehler zu berechnen und den Stream zu vervollständigen, indem Sie alle Beobachter abmelden
  • Complete, um den Stream als abgeschlossen zu markieren und alle Beobachter abzumelden

RAC hat zusätzlich, interrupteddass gesendet wird, wenn a Signalentsorgt wird, bevor entweder korrekt oder mit einem Fehler abgeschlossen wird.

Manuelles Schreiben

In RAC sind Signal/ SignalProducerschreibgeschützte Entitäten, sie können nicht von außen verwaltet werden, dasselbe gilt für ObservableRxSwift. Um ein Signal/ SignalProducerin eine schreibbare Entität zu verwandeln , müssen Sie die pipe()Funktion verwenden, um ein manuell gesteuertes Element zurückzugeben. Im Rx-Bereich ist dies ein anderer Typ Subject.

Wenn das Lese- / Schreibkonzept ungewohnt klingt, kann eine schöne Analogie zu Future/ Promisehergestellt werden. A Futureist ein schreibgeschützter Platzhalter, wie Signal/ SignalProducerund Observableandererseits Promisekann a manuell erfüllt werden, wie für pipe()und Subject.

Scheduler

Diese Entität ist in beiden Welten ziemlich ähnlich, dieselben Konzepte, aber RAC ist nur seriell, stattdessen bietet RxSwift auch gleichzeitige Scheduler.

Komposition

Die Komposition ist das Hauptmerkmal der reaktiven Programmierung. Das Erstellen von Streams ist die Essenz beider Frameworks. In RxSwift werden sie auch als Sequenzen bezeichnet .

Alle beobachtbaren Entitäten in RxSwift sind vom Typ ObservableType, daher erstellen wir Instanzen von Subjectund Observablemit denselben Operatoren ohne zusätzliche Bedenken.

Auf RAC-Raum, Signalund SignalProducersind 2 verschiedene Entitäten und wir müssen liftauf SignalProducerin der Lage sein, zu komponieren, was mit Instanzen von produziert wird Signal. Die beiden Entitäten haben ihre eigenen Operatoren. Wenn Sie also Dinge mischen müssen, müssen Sie sicherstellen, dass ein bestimmter Operator verfügbar ist. Auf der anderen Seite vergessen Sie die heißen / kalten Observablen.

Über diesen Teil hat Colin Eberhardt es gut zusammengefasst:

Mit Blick auf die aktuelle API konzentrieren sich die Signaloperationen hauptsächlich auf das 'nächste' Ereignis, sodass Sie Werte transformieren, überspringen, verzögern, kombinieren und auf verschiedenen Threads beobachten können. Während sich die Signalproduzenten-API hauptsächlich mit den Signallebenszyklusereignissen (abgeschlossen, Fehler) befasst, werden Operationen wie then, flatMap, takeUntil und catch ausgeführt.

Extra

RAC hat auch das Konzept von Actionund Propertydas erstere ist ein Typ zur Berechnung von Nebenwirkungen, die sich hauptsächlich auf die Benutzerinteraktion beziehen. Das letztere ist interessant, wenn ein Wert beobachtet wird, um eine Aufgabe auszuführen, wenn sich der Wert geändert hat. In RxSwift die Actionübersetzt wieder in ein Observable, ist dies schön in gezeigt RxCocoa, eine Integration von Rx Primitiven sowohl für iOS und Mac. Die RACs können in RxSwift Propertyin Variable(oder BehaviourSubject) übersetzt werden.

Es ist wichtig zu verstehen, dass Property/ Variabledie Art und Weise ist, wie wir die imperative Welt mit dem deklarativen Charakter der reaktiven Programmierung verbinden müssen. Daher ist dies manchmal eine grundlegende Komponente, wenn es um Bibliotheken von Drittanbietern oder Kernfunktionen des iOS / Mac-Bereichs geht.

Fazit

RAC und RxSwift sind zwei völlig unterschiedliche Bestien. Ersteres hat eine lange Geschichte im Kakao-Raum und viele Mitwirkende. Letzteres ist noch recht jung, stützt sich jedoch auf Konzepte, die sich in anderen Sprachen wie Java, JS oder als wirksam erwiesen haben .NETZ. Die Entscheidung, welche besser ist, wird bevorzugt. RAC gibt an, dass die Trennung von heiß / kalt beobachtbar notwendig war und dass dies das Kernmerkmal des Frameworks ist. Laut RxSwift ist die Vereinheitlichung besser als die Trennung. Auch hier geht es nur darum, wie Nebenwirkungen verwaltet / durchgeführt werden.

RAC 3.0 scheint eine unerwartete Komplexität eingeführt zu haben, zusätzlich zu dem Hauptziel, heiße / kalte Observable zu trennen, wie das Konzept der Unterbrechung, die Aufteilung von Operatoren zwischen zwei Entitäten und die Einführung eines zwingenden Verhaltens start, um mit der Erzeugung von Signalen zu beginnen. Für manche Menschen können diese Dinge eine nette Sache oder sogar eine Killer-Funktion sein, für andere können sie einfach unnötig oder sogar gefährlich sein. Eine andere Sache, an die Sie sich erinnern sollten, ist, dass RAC versucht, so weit wie möglich mit den Kakao-Konventionen Schritt zu halten. Wenn Sie also ein erfahrener Kakao-Entwickler sind, sollten Sie sich wohler fühlen, damit zu arbeiten, als mit RxSwift.

RxSwift hingegen lebt mit allen Nachteilen wie heißen / kalten Observablen, aber auch den guten Dingen von Reactive Extensions. Der Wechsel von RxJS, RxJava oder Rx.Net zu RxSwift ist eine einfache Sache. Alle Konzepte sind gleich. Daher ist es ziemlich interessant, Material zu finden. Vielleicht ist das gleiche Problem, mit dem Sie jetzt konfrontiert sind, von jemandem in RxJava und der Lösung gelöst worden kann unter Berücksichtigung der Plattform erneut angewendet werden.

Welches ausgewählt werden muss, ist definitiv eine Frage der Präferenz, aus objektiver Sicht ist es unmöglich zu sagen, welches besser ist. Die einzige Möglichkeit besteht darin, Xcode abzufeuern, beide auszuprobieren und den auszuwählen, mit dem Sie besser arbeiten können. Es handelt sich um zwei Implementierungen ähnlicher Konzepte, mit denen versucht wird, dasselbe Ziel zu erreichen: die Vereinfachung der Softwareentwicklung.

bontoJR
quelle
24
Dies ist eine großartige Erklärung, @ junior-b! Erwähnenswert ist jedoch auch, dass RAC Typinformationen (einschließlich fehlender Fehler dank NoError) in den Stream-Typen selbst codiert : Signal<T, E: ErrorType>versus Observable<T>. Dies sowie die Heiß / Kalt-Trennung bieten eine größere Menge an Informationen zur Kompilierungszeit, die Sie einfach nicht haben RxSwift.
NachoSoto
3
Hallo @nachosoto, danke für das freundliche Wort. Ich denke, der vorgeschlagene Zusatz würde nicht so gut in einen Vergleich über reaktive Programmierung passen. Es ist definitiv eine nette Ergänzung auf der Seite des RAC, aber für mich geht es bei RP darum, die Datenflussprogrammierung zu vereinfachen, und wichtige Faktoren sind: Fehlerbehandlung, asynchrone Berechnung, Management von Nebenwirkungen und Komposition. Aus Entwicklersicht scheint dies eine nette Funktion zu sein. Dies dient zur Verdeutlichung des Fehlertyps im Code. Es verbessert den Aspekt der Fehlerbehandlung des Frameworks nicht wirklich. Dies ist natürlich meine bescheidene Meinung.
bontoJR
3
Es ist erwähnenswert, dass es derzeit an anständigen Tutorials zu RAC mangelt, es jedoch einige großartige Beispielprojekte für RxSwift gibt, die für mich entscheidend waren.
Vadim Bulavin
1
ReactiveCocoa war gut, bis sie freie Funktionen, SignalProducer, generisch mit Fehler einführten. Ich lerne RxSwift und ich habe die gleiche Erfahrung bei der Arbeit mit RxKotlin, RxJS
onmyway133