Học Rxswift cấp tốc trong 10 phút 👨🏻‍💻

Sau 2 tháng tìm hiều về Rxswift hôm nay mình xin mạn phép, chia sẻ những gì mà mình học được trong 2 tháng vừa qua .Để không làm mất thời gian bài viết này mình sẽ chỉ nói sơ qua về khái niệm, mà không đi sâu vào cụ thể của từng thành phần, và mình cũng sẽ code để demo các cách thức hoạt động của các thành phần để xem nó ra sao . Dân IT nên thích làm hơn là học lý thuyết suông, có người từng bảo với mình rằng “Nên làm để học thay vì học để làm “ điều đó sẽ thấy thú vị hơn là học một đống lý thuyết, mà không áp dụng được vào thực tế, sau bao năm ngẫm lại vẫn thấy anh ấy nói đúng. Mong rằng bài viết sẽ hữu ích cho các bạn mới tiếp cận với RxSwift.

RxSwift là gì

RxSwift là một phiên bản Reactive Extension được viết bằng ngôn ngữ Swift. ReactiveX là sự kết hợp của những ý tưởng hay nhất từ Observer pattern, Iterator pattern và functional programming. RxSwift sẽ giúp công việc của bạn trở nên đơn giản hơn. Thay cho notifications, một đối tượng khó để test, ta có thể sử dụng signals. Thay cho delegates, thứ tốn rất nhiều code, ta có thể viết blocks và bỏ điswitches/ifs lồng nhau. Ta còn có thể sử dụng KVO, IBActions, filters, MVVM và nhiều tiện ích khác được hỗ trợ mượt mà trong RxSwift.

1 Observable Sequences 🎞

Đầu tiên bạn cần phải hiểu mọi thứ trong Rxswift là observable sequence từ subscribes đến xử lý sự kiện thông qua bởi một observable sequence. Các kiểu dữ liệu như Array String hoặc Dictionary sẽ được convert sang một observable sequence hoặc bất cứ đối tượng nào tuân theo Sequence Protocol của Swift Standard Library

Tạo một vài observable sequences xem thế nào nhé

   
   let helloSequence = Observable.just("Hello Rx")
   let fibonacciSequence = Observable.from([0,1,1,2,3,5,8])
   let dictSequence = Observable.from([1:"Hello",2:"World"])

Bạn đăng ký một observable sequences bằng câu lệnh subscribe(on:(Event)-> ()).

Qua block sẽ nhận được tất cả events được phát ra bởi sequence.

   
   let helloSequence = Observable.of("Hello Rx")
   let subscription = helloSequence.subscribe { event in
     print(event)
   }
   OUTPUT: 
   next("Hello Rx") 
   completed
   

Observable sequences có thể phát ra không hoặc nhiều event trong vòng đời của nó Trong Rxswift một Event như một Enumeration Type (Nôm na là danh sách các trường hợp )có với 3 trạng thái

.next(value: T) — xảy ra khi một hay một tập hợp các giá trị được bổ sung thêm vào Observable sequences, nó sẽ gửi next event cho các subscribers đã đăng ký ở ví dụ trên.

.error(error: Error) — Nếu gặp phải Error một chuỗi sẽ phát ra sự kiện lỗi , và sẽ kết thúc Observable sequences

.completed — Nếu một chuỗi kết thúc nó sẽ gửi event hoàn thành gửi đến cho các subscribers

2 Subjects

PublishSubject

Chỉ phát ra sự kiện mới nhất của subscribers , do đó bất cứ sự kiện nào trước subscribers sẽ không được phát ra Ví dụ thực tế publish giống như một thằng vào lớp muộn nhưng chỉ cần nghe 1 điểm nó cần nghe

code example

     let subject = PublishSubject<String>()

     subject.onNext("Emmit 1")

     subject.subscribe(onNext: { (event) in

     print("event \(event)")
     }).disposed(by: disposeBag)

     subject.onNext("Emmit 2")

Kết quả sẽ là event Emmit 2

BehaviourSubject

1 behavior subject lưu các các next event() gần nhất, và phát lại cho subscriber mới behavior subject cũng giống với publishsubject chỉ khác behavior subject bắt đầu bằng một gía trị mặc định khi khởi tạo, giá trị này có thể bị gi đè ngay sau khi , phần tử mới được thêm vào

code example

     let subject = BehaviorSubject(value: "")
     subject.onNext("Issue 1")

     subject.subscribe(onNext: { (event) in

     print("event \(event)")

     }).disposed(by: disposeBag)

     subject.onNext("Issue 2")

Kêt quả sẽ là

event Issue 1 event Issue 2

ReplaySubject

Là khởi tạo với một kích thước bộ đệm lưu các phần tử gần nhất vào bộ nhớ đệm và sau đó phát lại các phần tử có trong bộ nhớ đệm cho subcriber mới

code example

     let replaySub = ReplaySubject<String>.create(bufferSize: 2)

     replaySub.onNext("Issue #1")
     replaySub.onNext("Issue #2")
     replaySub.onNext("Issue #3")
     replaySub.onNext("Issue #5")
     replaySub.onNext("Issue #6")
     replaySub.onNext("Issue #7")

     replaySub.subscribe { (event) in
         
         print("event \(event)")
     }

Kết quả sẽ là: event next(Issue #6) event next(Issue #7)

3 Combining Observables

Merger

merge() cho phép kết hợp nhiều Obseravble bằng cách gộp cái emit lại với nhau

Bạn có thể kết hơp nhiều output của nhiều Obseravble thành một Obseravble khi sử dụng Merger operator

.merge() complete chỉ khi tất cả các Inner Sequence và source Observable đều complete.

Các Inner Sequence hoạt động đọc lập không liên quan với nhau.

Nếu bết kỳ Inner Sequence nào emit Error thì Source Observable ngay lập tức emit ra Error và terminate. code example

     let left = PublishSubject<Int>()
     let right = PublishSubject<Int>()

     let source = Observable.of(left.asObserver(),right.asObserver())
     let obserable  = source.merge()
     obserable.subscribe(onNext: { (event) in
     print(event)
     }, onError: nil , onCompleted: nil)

     left.onNext(1)
     right.onNext(4)
     left.onNext(2)
     left.onNext(3)

     right.onNext(5)
     right.onNext(6)

Kết quả là 1,4,2,3,5,6

Concat

Concat tương tư như hoạt động của merge() sự khác nhau nằm ở chỗ concat sẽ đợi các luồng trước kết thúc trước rồi đến các luồng sau, còn merger() thì bạn có thể thay thế output

👉🏼Lưu ý bạn chỉ có thể nối các chuỗi có cùng kiểu dữ liệu với nhau, nếu nối khác kiểu sẽ báo lỗi

Example


let obserable = Observable.concat([left,right])

obserable.subscribe(onNext: { (event) in

print("event \(event)")

}, onError: nil , onCompleted: nil).disposed(by: disposeBag)

left.onNext(1)
right.onNext(4)
left.onNext(2)
left.onNext(3)
right.onNext(6)

Kết quả sẽ là
event 1 event 2 event 3

👉 Lý do 4 không chạy vì luồng left chưa kết thúc nên 4 sẽ không được hiển thị

Start with

StartWith được sử dụng khi ta muốn phát sinh sự kiện với một tập giá trị nào đó, sau đó mới phát sinh các tập giá trị được định nghĩa trong Observable.
Code example

  
 func startWith(){
         let number = Observable.of(4,5,6)
         let obserable = number.startWith(1,2,3)
         obserable.subscribe(onNext: { (event) in
             print("event \(event)")
             
         }, onError: nil, onCompleted: nil, onDisposed: nil).dispose()
        
     }

Kết quả lúc này sẽ là

1,2,3,4,5,6,7

### 4 RxSwift Transforming

map

Rxswift map hoạt động tương tự thư viện chuẩn của swift điểm khác biệt là nó hoạt động trong một observables hép biến đổi Map cho phép ta thực hiện biến đổi ứng với từng phần tử trong Observable Sequence trước khi gửi tới Subscribe code example

  
  let observable1 = Observable.of(1,2,3)

  observable1.map {
      
      return  $0 * 2
  }.subscribe(onNext: { (event) in
      print("event \(event)")
  }).disposed(by: disposeBag)
  

Kết quả sẽ là 2,4,6

flat map

Đinh nghĩa flatMap biến đổi các thành phần phát ra bởi một Observable trong thành nhiểu Observable sau đó gộp lại thành một Observable duy nhất code example

  struct Player {
      var score:BehaviorRelay<Int>
      
  }
  
  let kevin  = Player(score: BehaviorRelay(value: 50))
  
  let player = PublishSubject<Player>()
  
  player.asObservable().flatMap { $0.score.asObservable()}.subscribe(onNext: { (event) in
      
      print("event \(event)")
      }).disposed(by: disposeBag)
  
  player.onNext(kevin)
  
  

Kết quả lúc này sẽ là event 50

flatMapLatest

Sự khác biệt giữa flatMap và flatMapLatest là nó huỷ trước khi subscription khi subscription xảy ra

  
      let outerObservable = Observable<Int>.interval(0.5, scheduler: MainScheduler.instance).take(2)
      let combineObservable = outerObservable.flatMapLatest {  value in
      return Observable<NSInteger>.interval(0.3, scheduler: MainScheduler.instance).take(3).map {  inerValue in
      print("Outer value \(value) Iner Value \(inerValue)")
      }
      }
      combineObservable.subscribe(onNext: { (event) in
      print("event \(event)")
      }, onError: nil, onCompleted: nil).disposed(by: disposeBag)

Kết quả sẽ là

Outer value 0 Iner Value 0 event () Outer value 1 Iner Value 0 event () Outer value 1 Iner Value 1 event () Outer value 1 Iner Value 2 event ()

Filtering Operators

Element at

Sẽ lấy một phần tử nằm ở một vị trí xác định trong chuỗi mà bạn muốn nhận được và bỏ qua

   
         let observable1 = Observable.of(1,2,3)

        observable1.elementAt(2).subscribe(onNext: { (event) in
            print("event: \(event)")
        }).disposed(by: disposeBag)
   

Kết quả lúc này sẽ là 3

Filter

Chỉ phát ra những phần tử thoả mãn điều kiện code example

  
      let observable1 = Observable.of(1,2,3,4,5,6)
      
      observable1.filter { $0 % 2 == 0
      
      }.subscribe(onNext: { (event) in
      
      print("event \(event)")
      }).disposed(by: disposeBag)
  

### Skipping operators Cho phép bỏ qua phần tử khi truyền vào 1 prametter

code example

    let observable1 = Observable.of("A","B","C","D","E","F")
  
    observable1.skip(0).subscribe { (event) in
  
  print(event)
  }.disposed(by: disposeBag)
  
  

kêt quả sẽ là next(B) next(C) next(D) next(E) next(F) completed ### skipWhile

Take

Phát ra phần tử đầu tiên thứ n trong chuỗi n-> là parmater truyền vào take ()

code example

  
   Observable.of(1,2,3,4,5,6).take(2).subscribe { (event) in
       
       print(event)
   }.disposed(by: disposeBag)

Kết quả sẽ là 1,2

Take while

Take while Đối chiếu nhiều item đuợc phát ra bởi môt Observable cho đến khi một điều kiện cụ thể false

code example

        Observable.of(2,4,6,7,5,8,10).takeWhile {
            
            return $0 % 2  == 0 
        }.subscribe(onNext: { (event) in
            print(event)
            }).disposed(by: disposeBag)

Take while sẽ đối chiếu nguồn Observable cho đến khi điều kiện false thì TakeWhile dừng việc đối chiếu nguồn Observable và kết thúc Observable

Take until

Loại bỏ bất kỳ items nào được phát ra bởi một Observable sau 1 giây Observable phát ra 1 item hoặc kết thúc

code example

let subject = PublishSubject<String>()
        let trigger = PublishSubject<String>()
        
        subject.takeUntil(trigger).subscribe(onNext: { (event) in
            
            print(event)
            
        }).disposed(by: disposeBag)
        
        subject.onNext("event 1")
        trigger.onNext("X")

        subject.onNext("event 2")
        
        trigger.onNext("event 3")

kết quả sẽ là 1

Ứng dụng thực tế

Bài viết này là những gì mình học được trong những ngày tháng tiếp cận với Rx swift nên không thể trách nhiều thiếu sót mong các bậc cao nhân góp ý giúp mình để mình cải thiện trong bài viết sau
mọi thông tin góp ý xin gửi về địa chỉ phamtrungkiendev@gmail.com

*Bài viết này được tham khảo theo nguồn

Written on December 28, 2019