RxSwift pour les nuls - Partie 1
Savoir utiliser RxSwift dans son projet iOS est un vrai plus. Parmi ses avantages, on peut lister : améliorer l'expérience utilisateur, et permettre une bonne gestion des threads. De plus, cette librairie, basée sur les observables, va permettre d’écrire un code asynchrone d’une manière plus concise et compacte. A titre d'information, le préfixe Rx dans RxSwift signifie “ReactiveX”.
Pour utiliser RxSwift, il faut tout d'abord l’installer en utilisant la gestion des dépendances (CocoaPods, Carthage ou bien Swift Package Manager). Dans cet article, nous aborderons tout d'abord la programmation réactive. Ensuite nous explorerons les observables. Enfin, nous verrons ce que sont les subjects.
Programmation réactive
La programmation réactive est un paradigme de programmation, c’est-à-dire un modèle de programmation basé sur des observables et les événements qui y sont liés.
Dans la programmation réactive, on crée un flux de données, c’est-à-dire des données disponibles au fils du temps qui réalisent de manière ordonnée des actions X ou Y. On peut diviser ce flux en deux parties. La première partie, considérée comme la source d’émission des données, les émet. En même temps, la deuxième partie elle, "écoute" et récupère cette émission.
Maintenant que vous avez le bagage minimum requis, on peut passer à la suite. Dans les parties suivantes, je vais traiter des Observables qui sont le coeur du RxSwift ainsi que des Subjects.
Les Observables
Un Observable ? C’est quoi ? Le framework RxSwift est basé sur les observables. En RxSwift on les appelle “Observable sequence” alors que pour les autres plateformes, c’est bien “Observable streams”. Les observables sont donc une séquence d'éléments qui peuvent émettre des valeurs. Ces valeurs peuvent être des Int, String ou bien un autre Object.
Imaginons que l'observable soit une chaîne youtube et que les observers soient des abonnés. A chaque fois qu'une vidéo sera ajoutée à la chaine, les abonnés seront notifiés de son arrivée. Découvrons comment implémenter tout ça en utilisant les Operators :
import RxSwift let observable1 = Observable.just(1) let observable2 = Observable.of(1,2,3) let observable3 = Observable.of([1,2,3]) let observable4 = Observable.from([1,2,3,4,5])
- just( ): Ici on a créé un observable qu’on a nommé “observable1” en utilisant la classe Observable. Cette classe contient plusieurs méthodes qui permettent de créer un observable. Pour cet exemple on a utilisé la méthode "just". Elle retourne une séquence qui contient un et un seul élément. Dans notre cas il s'agit de 1. Après avoir créé notre premier observable avec la méthode "just", on peut en créer d'autres. Dans ce cas, on utilisera alors "of" qui va nous permettre de créer une séquence d’éléments différents, comme c'est le cas pour l'observable2. Si on souscrit à ses éléments, on récupérera les valeurs 1, 2 et 3. Notez qu'ici, le type d’observable est Observable<Int>, alors que pour l'observable3, il s'agit de Observable<[Int]>.
- from( ): Ici on a utilisé “from” pour créer un Observable qui prend un array d’éléments comme paramètre et le convertit. Notez bien que le type de l’Observable est Observable<Int> On vient de créer nos observables qui émettent les events, mais c’est quoi la prochaine étape me direz-vous ? La prochaine étape, c'est de recevoir ce qui a été émis. En un autre terme plus technique : “To subscribe”
Subscribing Quand on souscrit à un observable, on reçoit les événements émis par celui-ci. L’événement a trois états. En effet, c’est une énumération qui a trois “case” :
- next
- error
- completed
On souscrit en utilisant “subscribe” qui prend une closure en tant que paramètre.
import RxSwift let observable = Observable.from([1,2,3,4,5]) observable.subscribe { event in print(event) } /* Résultat Console: next(1) next(2 next(3) next(4) next(5) completed
Mais comment récupérer les valeurs 1, 2, 3, 4 et 5 ? C’est simple, en utilisant .element :
import RxSwift let observable = Observable.from([1,2,3,4,5]) observable.subscribe { event in if let element = event.element { print(element) } } /* Résultat Console: 1 2 3 4 5 */
Il existe une autre méthode pour pouvoir accéder aux éléments d’un observateur sans avoir à unwrapper, en utilisant subscribe(onNext) :
import RxSwift let observable = Observable.from([1,2,3,4,5]) observable.subscribe(onNext: { element in print(element) }) /* Résultat Console: 1 2 3 4 5 */
Notez que le completed event n’est pas affiché. Dispose Bag Quand on crée une subscription, elle nous retourne un subscriber et ce dernier sera toujours là pour observer cette séquence. Du coup il faut être sûr de disposer de ces subscribers. Si on ne les dispose pas on aura une fuite de mémoire. Il existe 2 méthodes pour disposer, en utilisant dispose() ou bien disposeBag : Passons à la pratique. Dans le premier exemple on utilisera dispose() et pour le deuxième DisposeBag()
import RxSwift let observable = Observable.from([1,2,3,4,5]) let subscription = observable.subscribe(onNext: { element in print(element) }) subscription.dispose()
import RxSwift
let disposeBag = DisposeBag()
Observable.of("A", "B", "C").subscribe {
print($0)
}.disposed(by: disposeBag)
Subjects
Subject est à la fois un Observable et un Observer. Yes, 2 in 1. En RxSwift, il existe plusieurs types de subjects. Dans cet article je n'en mentionnerai que de trois, qui sont : Publish Subject, Behavior Subject, Replay Subject.
Publish Subject
Publish Subject émet les nouveaux événements seulement aux nouveaux souscrits. Si d’autres événements ont été ajoutés au subject avant la souscription d’un subscriber, il ne vas pas les recevoir.
import RxSwift
let subject = PublishSubject<String>() // (1)
subject.onNext("Something1")
subject.subscribe { event in //(2)
print(event)
}
subject.onNext("Something2")
subject.onNext("Something3")
subject.dispose() //(3)
subject.onNext("Something4")
/*
Résultat Console:
next(Something2)
next(Something3)
*/
(1) : Ici le subject est une séquence vide. (2) : Si on exécute, on ne verra pas la souscription. La raison est qu’on a créé la subscription après avoir créé l’événement (il n'y a pas de subscribers ). Mais si on a créé l’événement après la souscription, on peut du coup les récupérer. On pourrait comparer cela à un utilisateur Instagram qui ne peut pas voir les nouveautés d'un compte (les events) tant qu'il n'en est pas abonné (souscrit). (3) : toutes les souscriptions qui arrivent après le dispose seront négligées, même l’événement completed est ignoré.
Behavior Subject
Parfois on voudrait que le subscriber reçoive l’événement le plus récent même s’il souscrit après. Le Behavior Subject va renvoyer le dernier événement ou bien la valeur initiale, dans le cas où il n’y a pas d'événements récents avant sa souscription ainsi que d'événements après la souscription. Notez que le Behavior Subject doit absolument être initialisé par une valeur qui sera considérée comme le premier next event.
import RxSwift let disposeBag = DisposeBag() let subject = BehaviorSubject(value: "First") subject.subscribe { (event) in print(event) }.disposed(by: disposeBag) subject.onNext("Second") subject.onNext("Third") subject.onNext("Fourth") /* Résultat Console: next(First) next(Second) next(Third) next(Fourth) */
import RxSwift
let disposeBag = DisposeBag()
let subject = BehaviorSubject(value: "First")
subject.onNext("Before Subscribing")
subject.onNext("Before Subscribing 2")
subject.subscribe { (event) in
print(event)
}.disposed(by: disposeBag)
subject.onNext("Second")
subject.onNext("Third")
subject.onNext("Fourth")
/*
Résultat Console:
next(Before Subscribing 2)
next(Second)
next("Third")
next(Fourth)
*/
Behavior Subject est à peu près similaire à Publish Subject. La seule différence est que pour qu’il puisse être initialisé, on doit au moins lui passer une valeur initiale.
Notez que dans le premier exemple, le subscriber a été initialisé avec la valeur “First” et qu'il n’y avait pas d’autres événements avant la souscription. C’est donc la seule valeur prise en compte avant celle-ci. Or dans ce deuxième exemple, deux events ont eu lieu avant la souscription et le seul event pris en compte est le plus récent qui est “Before Subscribing 2”
Replay Subject
On vient de voir 2 types de subjects, le Publish Subject ainsi que le Behavior Subject. Regardons un peu ce que fait le Replay Subject. Replay Subject émet un nombre spécifique d’événements avant la souscription. Ce nombre est la valeur du buffer.
import RxSwift
let disposeBag = DisposeBag()
let subject = ReplaySubject<String>.create(bufferSize: 2)
subject.onNext("Premier")
subject.onNext("Deuxième")
subject.onNext("Troisième")
subject.subscribe { event in
print(event)
}.disposed(by: disposeBag)
subject.onNext("Quatrième")
subject.onNext("Cinquième")
subject.onNext("Sixième")
/*
Résultat Console:
next(Deuxième)
next(Troisième)
next(Quatrième)
next(Cinquième)
next(Sixième)
*/
Replay subjects fait passer les derniers événements en se basant sur la longueur du buffer précisé lors de la création du subject.
Conclusion
C’est tout pour cette première partie. J’espère que c’était une découverte intéressante de RxSwift et plus spécialement de ce que sont les Observables, les Subscribers ainsi que les Subjects. Une deuxième partie arrivera bientôt où je traiterai des “Filtering Operators”, “Transforming Operators” ainsi que des “Combing Operators”. Stay tuned !
Auteur(s)
Vous souhaitez en savoir plus sur le sujet ?
Organisons un échange !
Notre équipe d'experts répond à toutes vos questions.
Nous contacter