ReactiveCocoa vs RxSwift - zalety i wady?

256

Więc teraz dzięki swift ludzie ReactiveCocoa przepisali go w wersji 3.0 dla swift

Pojawiło się też inne przedsięwzięcie o nazwie RxSwift .

Zastanawiam się, czy ludzie mogliby dodać informacje o różnicach w projekcie / api / filozofii obu ram (proszę, w duchu SO, trzymaj się rzeczy, które są prawdziwe, a nie opinii o tym, co jest najlepsze)

[Uwaga dla modów StackOverflow: To pytanie NIE ma ostatecznych odpowiedzi, odpowiedzią są różnice między tymi dwoma frameworkami. Myślę, że jest to również temat na SO]

Na początek moje pierwsze wrażenie z przeczytania ich ReadMe to:

  • Jako osoba znająca „prawdziwy” C # Rx firmy Microsoft, RxSwift wygląda o wiele bardziej rozpoznawalnie.
  • Wygląda na to, że ReactiveCococa weszła teraz w swoją własną przestrzeń, wprowadzając nowe abstrakcje, takie jak Sygnały kontra SignalProducers i Lifting. Z jednej strony wydaje się to wyjaśniać niektóre sytuacje (co to jest sygnał Hot vs. Cold), ale z drugiej strony wydaje się, że zwiększa to złożoność frameworka
Orion Edwards
źródło
Twoje pytanie dotyczy w szczególności „opinii”. Czy mógłbyś przeredagować? Z przyjemnością wycofam wtedy mój głos.
Sulthan
2
Możesz pozbyć się „dodawania ich opinii”, ponieważ różnice są faktami, a nie opiniami. Następnie możesz polubić lub nie lubić niektórych funkcji RAC / RxSwift, ale różnice są krystalicznie czyste.
bontoJR
1
hahaha, dobry ruch dotyczący „notatki do modów”!
ming yeow
1
Zmień nazwę pytania: Różnica między ReactiveCocoa i RxSwift. Myślę, że wszystko stanie się „faktem”, a to pytanie jest dziedzictwem.
2016 r
1
Nawet rozwiązanie zaczyna się od „To bardzo dobre pytanie”. : |
Iulian Onofrei

Odpowiedzi:

419

To jest bardzo dobre pytanie. Porównywanie dwóch światów jest bardzo trudne. Rx to port Reaktywnych rozszerzeń w innych językach, takich jak C #, Java lub JS.

Reactive Cocoa został zainspirowany przez funkcjonalne programowanie reaktywne , ale w ostatnich miesiącach został również wskazany jako zainspirowany również przez Reactive Extensions . Rezultatem jest struktura, która dzieli niektóre rzeczy z Rx, ale ma nazwy pochodzące z FRP.

Pierwszą rzeczą do powiedzenia jest to, że ani RAC, ani RxSwift nie są implementacjami Funkcjonalnego Reaktywnego Programowania , zgodnie z definicją Conala . Od tego momentu wszystko można sprowadzić do tego, jak każda struktura obsługuje efekty uboczne i kilka innych składników.

Porozmawiajmy o społeczności i rzeczach związanych z meta-technologią :

  • RAC to 3-letni projekt, który powstał w Objective-C, później przeniesiony do Swift (z mostami) w wersji 3.0, po całkowitym porzuceniu trwających prac nad Objective-C.
  • RxSwift to kilkumiesięczny projekt i wydaje się, że ma teraz rozpęd w społeczności. Jedną z ważnych rzeczy dla RxSwift jest to, że należy do organizacji ReactiveX i że wszystkie inne implementacje działają w ten sam sposób. Nauczenie się, jak radzić sobie z RxSwift sprawi, że praca z Rx.Net, RxJava lub RxJS będzie prostym zadaniem i tylko kwestią składni języka. Mógłbym powiedzieć, że opiera się na filozofii, ucz się raz, stosuj wszędzie .

Teraz czas na rzeczy techniczne.

Produkcja / obserwacja podmiotów

RAC 3.0 ma 2 główne jednostki, Signala SignalProducerpierwsza publikuje zdarzenia bez względu na to, czy subskrybent jest przyłączony czy nie, a druga wymaga startwygenerowania sygnałów / zdarzeń. Ten projekt został stworzony, aby oddzielić nużącą koncepcję obserwowalnych na gorąco i na zimno, co było źródłem zamieszania dla wielu programistów. Dlatego różnice można ograniczyć do sposobu radzenia sobie z efektami ubocznymi .

W RxSwift Signali SignalProducerprzekłada się na Observable, może to zabrzmieć myląco, ale te dwie istoty są w rzeczywistości takie same w świecie Rx. Projekt z ObservableR w RxSwift musi zostać utworzony, biorąc pod uwagę, czy są gorące czy zimne, może to zabrzmieć jako niepotrzebna złożoność, ale gdy zrozumiesz, jak działają (i ponownie gorący / zimny / ciepły dotyczy tylko skutków ubocznych podczas subskrybowania / obserwowania ) można je oswoić.

W obu światach koncepcja subskrypcji jest w zasadzie taka sama, istnieje jedna niewielka różnica, którą wprowadził RAC, i jest to interruptionwydarzenie, w którym a Signaljest usuwane przed wysłaniem zdarzenia zakończenia. Podsumowując, oba mają następujące rodzaje zdarzeń:

  • Next, aby obliczyć nową otrzymaną wartość
  • Error, aby obliczyć błąd i ukończyć strumień, anulując subskrypcję wszystkich obserwatorów
  • Complete, aby oznaczyć strumień jako zakończony, anulując subskrypcję wszystkich obserwatorów

RAC dodatkowo ma interruptedto, że jest wysyłane, gdy a Signaljest usuwane przed ukończeniem poprawnie lub z błędem.

Pisanie ręczne

W RAC Signal/ SignalProducersą jednostkami tylko do odczytu, nie można nimi zarządzać z zewnątrz, to samo dotyczy ObservableRxSwift. Aby zmienić a Signal/ SignalProducerw jednostkę, która może zapisywać, musisz użyć pipe()funkcji, aby zwrócić ręcznie sterowany element. W przestrzeni Rx jest to inny typ o nazwie Subject.

Jeśli koncepcja odczytu / zapisu wydaje się nieznana, można dokonać przyjemnej analogii z Future/ Promise. FutureJest tylko do odczytu zastępczy, jak Signal/ SignalProducera Observable, z drugiej strony, Promisemogą być wypełniane ręcznie, jak na pipe()i Subject.

Harmonogramy

Ta jednostka jest bardzo podobna w obu światach, w tych samych koncepcjach, ale RAC jest tylko szeregowy, zamiast tego RxSwift oferuje również współbieżne harmonogramy.

Kompozycja

Kompozycja jest kluczową cechą programowania reaktywnego. Komponowanie strumieni jest istotą obu struktur, w RxSwift są one również nazywane sekwencjami .

Wszystkie podmioty RxSwift obserwowalne są typu ObservableType, więc komponować wystąpień Subjecti Observablez tych samych operatorów, bez żadnych dodatkowych obaw.

Na przestrzeni RAC, Signali SignalProducersą 2 różne podmioty i musimy liftna SignalProducer, aby móc komponować co jest produkowane z wystąpień Signal. Oba byty mają swoich operatorów, więc kiedy musisz mieszać różne rzeczy, musisz upewnić się, że określony operator jest dostępny, z drugiej strony zapominasz o obserwowalnych temperaturach na gorąco i na zimno.

O tej części Colin Eberhardt ładnie to podsumował:

Patrząc na bieżący interfejs API, operacje sygnału koncentrują się głównie na zdarzeniu „następnym”, umożliwiając przekształcanie wartości, pomijanie, opóźnianie, łączenie i obserwowanie różnych wątków. Podczas gdy interfejs API producenta sygnału dotyczy głównie zdarzeń cyklu życia sygnału (zakończonych, błędów), a także operacji, takich jak flatMap, takeUntil i catch.

Dodatkowy

RAC ma również koncepcję, Actiona Propertyten pierwszy jest typem do obliczania skutków ubocznych, głównie związanych z interakcją użytkownika, ten drugi jest interesujący, gdy obserwuje się wartość w celu wykonania zadania, gdy wartość się zmieniła. W RxSwift Actionponownie przekłada się na Observable, jest to dobrze pokazane RxCocoa, integracja prymitywów Rx na iOS i Mac. RAC Propertymożna przetłumaczyć na Variable(lub BehaviourSubject) w RxSwift.

Ważne jest, aby zrozumieć, że Property/ Variableto sposób, w jaki musimy połączyć imperatywny świat z deklaratywnym charakterem Reactive Programming, więc czasami jest to podstawowy element w kontaktach z bibliotekami stron trzecich lub podstawowymi funkcjami przestrzeni iOS / Mac.

Wniosek

RAC i RxSwift to 2 kompletnie różne bestie, ta pierwsza ma długą historię w przestrzeni kakaowej i wielu współpracowników, ta druga jest dość młoda, ale opiera się na koncepcjach, które okazały się skuteczne w innych językach, takich jak Java, JS lub .NETTO. Decyzja, która opcja jest lepsza, zależy od preferencji. RAC stwierdza, że ​​oddzielenie obserwowalnego gorącego / zimnego było konieczne i że jest to podstawowa cecha frameworka, RxSwift twierdzi, że ich unifikacja jest lepsza niż separacja, znowu chodzi tylko o to, jak efekty uboczne są kontrolowane / wykonywane.

Wydaje się, że RAC 3.0 wprowadził nieoczekiwaną złożoność nad głównym celem oddzielenia obserwowalnych wartości od gorących / zimnych, jak koncepcja przerwania, rozdzielenie operatorów między 2 byty i wprowadzenie pewnych zachowań koniecznych, takich jak startrozpoczęcie produkcji sygnałów. Dla niektórych osób te rzeczy mogą być miłe, a nawet zabójcze, dla innych mogą być niepotrzebne lub nawet niebezpieczne. Kolejną rzeczą do zapamiętania jest to, że RAC stara się jak najlepiej nadążać za konwencjami Cocoa, więc jeśli jesteś doświadczonym twórcą Cocoa, powinieneś czuć się bardziej komfortowo z nim pracować, niż z RxSwift.

Z drugiej strony RxSwift żyje ze wszystkimi wadami, takimi jak obserwowalne ciepło / zimno, ale także z dobrymi cechami Reactive Extensions. Przejście z RxJS, RxJava lub Rx.Net do RxSwift jest prostą rzeczą, wszystkie koncepcje są takie same, więc to sprawia, że ​​znalezienie materiału jest dość interesujące, być może ten sam problem, przed którym teraz stoisz, został rozwiązany przez kogoś w RxJava i rozwiązanie można ponownie zastosować, biorąc pod uwagę platformę.

To, który należy wybrać, jest zdecydowanie kwestią preferencji, z obiektywnego punktu widzenia nie można stwierdzić, który jest lepszy. Jedynym sposobem jest zwolnienie Xcode i wypróbowanie obu z nich i wybranie tego, z którym wygodniej jest pracować. Są to 2 implementacje podobnych koncepcji, starające się osiągnąć ten sam cel: uproszczenie tworzenia oprogramowania.

bontoJR
źródło
24
To świetne wytłumaczenie, @ junior-b! Warto również wspomnieć, że RAC koduje informacje o typie (w tym brak błędów dzięki NoError) w samych typach strumienia: Signal<T, E: ErrorType>kontra Observable<T>. To, podobnie jak separacja na gorąco i na zimno, zapewnia zwiększoną ilość informacji w czasie kompilacji, których po prostu nie masz RxSwift.
NachoSoto,
3
Cześć @nachosoto, dzięki za miłe słowo. Myślę, że proponowany dodatek nie pasowałby tak dobrze w porównaniu z programowaniem reaktywnym. Jest to zdecydowanie miły dodatek po stronie RAC, ale dla mnie RP dotyczy uproszczenia programowania przepływu danych, a ważnymi czynnikami są: obsługa błędów, obliczenia asynchroniczne, zarządzanie efektami ubocznymi i skład. Z perspektywy dewelopera wydaje się miłą funkcją, jest to do wyjaśnienia rodzaju błędu w kodzie, to tak naprawdę nie poprawia aspektu obsługi błędów w frameworku, to oczywiście moja skromna opinia.
bontoJR
3
Warto wspomnieć, że na chwilę obecną brakuje przyzwoitych samouczków na temat RAC, jednak istnieją świetne przykładowe projekty dla RxSwift, które były dla mnie decydujące.
Vadim Bulavin
1
ReactiveCocoa był dobry, dopóki nie wprowadzono bezpłatnych funkcji SignalProducer, ogólnych z błędem. Uczę się RxSwift i mam to samo doświadczenie podczas pracy z RxKotlin, RxJS
onmyway133