- vừa được xem lúc

Bài 9. RxSwift – Transforming Operators

0 0 9

Người đăng: Nguyen Khai Hoan

Theo Viblo Asia

1. Transforming elements

1.1. toArray

Việc nhận từng phần tử một thì rất tốn thời gian và đôi khi bạn muốn nhận hết một lèo tất cả phần tử của 1 Observable. Thì hãy dùng toán tử này toArray(). Nó sẽ giúp bạn gom tất cả phần tử được phát đi thành 1 array. Việc này sẽ thực hiện sau khi Observable kết thúc. Ví dụ:

 let bag = DisposeBag() Observable.of(1, 2, 3, 4, 5, 6) .toArray() .subscribe(onSuccess: { value in print(value) }) .disposed(by: bag)

Thực thi code trên, bạn sẽ thấy giá trị nhận được là một Array Int. Điểm đặc biệt ở đây là với toán tử toArray thì nó sẽ biến đổi Observable đó về thành là 1 Single. Khi đó chỉ cho phép là .onSuccess hoặc .error mà thôi.

1.2. map

  • Biến đổi từ kiểu dữ liệu này thành kiểu dữ liệu khác cho các phần tử nhận được
  • Việc biến đổi được xử lý bằng một closure
  • Sau khi biến đổi nếu bạn subscribe thì hãy chú ý tới kiểu dữ liệu mới đó, tránh bị nhầm lẫn.

Ví dụ:

let bag = DisposeBag() let formatter = NumberFormatter() formatter.numberStyle = .spellOut Observable<Int>.of(1, 2, 3, 4, 5, 10, 999, 9999, 1000000) .map { formatter.string(for: $0) ?? "" } .subscribe(onNext: { string in print(string) }) .disposed(by: bag)

Kết quả:

one
two
three
four
five
ten
nine hundred ninety-nine
nine thousand nine hundred ninety-nine
one million

Thêm toán tử .enumerated() lấy được index của các phần tử .

2. Transforming inner observables

Phần này sẽ dùng chung struct sau:

struct So { let soNguyen: BehaviorSubject<Int>
}

2.1. flatMap

  • Ta có 1 Observable gốc có kiểu dữ liệu cho các element của nó là 1 kiểu thuộc Observable
  • Vì các element có kiểu Observable ,thì nó có thể phát dữ liệu. Lúc này, chúng ta có rất nhiều stream phát đi
  • Muốn nhận được tất cả dữ liệu từ tất cả các element của Observable gốc, thì ta dùng toán tử flatMap
  • Chúng sẽ hợp thể tất cả các giá trị của các element đó phát đi thành 1 Observable ở đầu cuối. Mọi công việc subcirbe vẫn bình thường và ta không hề hay biết gì ở đây.

Ví dụ:

 let soDuong = So(soNguyen: BehaviorSubject(value: 1)) let soAm = So(soNguyen: BehaviorSubject(value: -1)) let subject = PublishSubject<So>() subject .flatMap { $0.soNguyen } .subscribe(onNext: { msg in print(msg < 0 ? "Số âm: \(msg)": "Số dương: \(msg)") }) .disposed(by: bag) subject.onNext(soDuong) soDuong.soNguyen.onNext(2) soDuong.soNguyen.onNext(3) soDuong.soNguyen.onNext(4) soDuong.soNguyen.onNext(5) subject.onNext(soAm) soDuong.soNguyen.onNext(6) soAm.soNguyen.onNext(-2) soDuong.soNguyen.onNext(7) soDuong.soNguyen.onNext(8) soAm.soNguyen.onNext(-3)

Kết quả:

Số dương: 1
Số dương: 2
Số dương: 3
Số dương: 4
Số dương: 5
Số âm: -2
Số dương: 6
Số dương: 7
Số dương: 8
Số âm: -3
  • Có 3 đối tượng luân phiên nhau phát dữ liệu
  • subject đóng vài trò là Observable gốc, sẽ phát đi các dữ liệu là các Observable khác
  • soDuong & soAm sẽ phát đi mà Int

2.2. flatMapLastest

Về cơ bản là giống như flatMap về việc hợp nhất các Observable lại với nhau. Tuy nhiên, điểm khác là nó sẽ chỉ phát đi giá trị của Observable cuối cùng tham gia vào. Ví dụ

  • Có 3 Observable là O1, O2 và O3 join vào lần lượt
  • flatMapLatest sẽ biến đổi các Observable đó thành 1 Observable duy nhất
  • Giá trị nhận được tại một thời điểm chính ta giá trị của phần tử cuối cùng join vào lúc đó

Ví dụ:

 let soDuong = So(soNguyen: BehaviorSubject(value: 1)) let soAm = So(soNguyen: BehaviorSubject(value: -1)) let subject = PublishSubject<So>() subject .flatMapLatest { $0.soNguyen } .subscribe(onNext: { msg in print(msg < 0 ? "Số âm: \(msg)": "Số dương: \(msg)") }) .disposed(by: bag) subject.onNext(soDuong) soDuong.soNguyen.onNext(2) soDuong.soNguyen.onNext(3) soDuong.soNguyen.onNext(4) soDuong.soNguyen.onNext(5) subject.onNext(soAm) soDuong.soNguyen.onNext(6) soAm.soNguyen.onNext(-2) soDuong.soNguyen.onNext(7) soDuong.soNguyen.onNext(8) soAm.soNguyen.onNext(-3)

Giống như flatMap nhưng giờ chúng ta thay toán tử flatMap thành flatMapLatest và kết quả nhận được:

Số dương: 1
Số dương: 2
Số dương: 3
Số dương: 4
Số dương: 5
Số âm: -1
Số âm: -2
Số âm: -3

Kể từ khi subject.onNext(soAm) thì soDuong dù đã phát ra thêm giá trị 6, 7, 8 nhưng không được in ra kết quả, đó là điểm khác nhau giữa flatMapflatMapLatest

2.3. Error, Completed

Thử với error hay completed

flatMapLatest

*** Error** Ví dụ:

 let soDuong = So(soNguyen: BehaviorSubject(value: 1)) let soAm = So(soNguyen: BehaviorSubject(value: -1)) let subject = PublishSubject<So>() subject .flatMapLatest { $0.soNguyen } .subscribe(onNext: { msg in print(msg < 0 ? "Số âm: \(msg)": "Số dương: \(msg)") }) .disposed(by: bag) subject.onNext(soDuong) soDuong.soNguyen.onNext(2) soDuong.soNguyen.onNext(3) soDuong.soNguyen.onNext(4) soDuong.soNguyen.onNext(5) soDuong.soNguyen.onError(MyError.anError) subject.onNext(soAm) soDuong.soNguyen.onNext(6) soAm.soNguyen.onNext(-2) soDuong.soNguyen.onNext(7) soDuong.soNguyen.onNext(8) soAm.soNguyen.onNext(-3)

Kêt quả:

Số dương: 1
Số dương: 2
Số dương: 3
Số dương: 4
Số dương: 5
Unhandled error happened: anError

Mọi thứ dùng lại ngay khi soDuong.soNguyen.onError(MyError.anError).

Thử tiếp một ví dụ tiếp theo:

 let soDuong = So(soNguyen: BehaviorSubject(value: 1)) let soAm = So(soNguyen: BehaviorSubject(value: -1)) let subject = PublishSubject<So>() subject .flatMapLatest { $0.soNguyen } .subscribe(onNext: { msg in print(msg < 0 ? "Số âm: \(msg)": "Số dương: \(msg)") }) .disposed(by: bag) subject.onNext(soDuong) soDuong.soNguyen.onNext(2) soDuong.soNguyen.onNext(3) soDuong.soNguyen.onNext(4) soDuong.soNguyen.onNext(5) subject.onNext(soAm) soDuong.soNguyen.onError(MyError.anError) soDuong.soNguyen.onNext(6) soAm.soNguyen.onNext(-2) soDuong.soNguyen.onNext(7) soDuong.soNguyen.onNext(8) soAm.soNguyen.onNext(-3)

Kết quả:

Số dương: 1
Số dương: 2
Số dương: 3
Số dương: 4
Số dương: 5
Số âm: -1
Số âm: -2
Số âm: -3

Vì sử dụng .flatMapLatest, nên khi subject.onNext(soAm) thì lúc soDuong.soNguyen.onError(MyError.anError) đã không còn hiệu lực.

*** Completed** Với Completed , ví dụ soDuong.soNguyen.onCompleted() tất cả những soDuong.soNguyen.onNext(_) sẽ không hoạt động. Còn lại, vẫn hoạt động bình thường.

flatMap

*** Error** Khác với .flatMapLatest, thì khi .onError thì .flatMap sẽ dừng lại luôn. Bạn có thể sửa ở ví dụ để hiểu chi tiết hơn. *** Completed** Với Completed tương tự như .flatMapLatest , ví dụ soDuong.soNguyen.onCompleted() tất cả những soDuong.soNguyen.onNext(_) sẽ không hoạt động. Còn lại, vẫn hoạt động bình thường.

2.4. materialize

Toán tử materialize sẽ biến đổi các event của Observable thành một element.

Ví dụ:

 let soDuong = So(soNguyen: BehaviorSubject(value: 1)) let soAm = So(soNguyen: BehaviorSubject(value: -1)) let subject = PublishSubject<So>() subject .flatMapLatest { $0.soNguyen.materialize() } .subscribe(onNext: { msg in print(msg) }) .disposed(by: bag) subject.onNext(soDuong) soDuong.soNguyen.onNext(2) soDuong.soNguyen.onNext(3) soDuong.soNguyen.onNext(4) soDuong.soNguyen.onError(MyError.anError) soDuong.soNguyen.onNext(5) subject.onNext(soAm) soDuong.soNguyen.onNext(6) soAm.soNguyen.onNext(-2) soDuong.soNguyen.onNext(7) soDuong.soNguyen.onNext(8) soAm.soNguyen.onNext(-3)

Kết quả:

next(1)
next(2)
next(3)
next(4)
error(anError)
next(-1)
next(-2)
next(-3)

flatMapLatest không bị dừng lại khi soDuong.soNguyen.onError(MyError.anError).

2.5. dematerialize

dematerialize thì ngược lại materialize. Giải nén các giá trị là events để lấy giá trị thật sự trong đó.

Ví dụ:

 let soDuong = So(soNguyen: BehaviorSubject(value: 1)) let soAm = So(soNguyen: BehaviorSubject(value: -1)) let subject = PublishSubject<So>() let subjectEvent = subject .flatMapLatest { $0.soNguyen.materialize() } subjectEvent.filter{ guard $0.error == nil else { print("Lỗi phát sinh: \($0.error!)") return false } return true } .dematerialize() .subscribe(onNext: { msg in print(msg) }) .disposed(by: bag) subject.onNext(soDuong) soDuong.soNguyen.onNext(2) soDuong.soNguyen.onNext(3) soDuong.soNguyen.onNext(4) soDuong.soNguyen.onError(MyError.anError) soDuong.soNguyen.onNext(5) subject.onNext(soAm) soDuong.soNguyen.onNext(6) soAm.soNguyen.onNext(-2) soDuong.soNguyen.onNext(7) soDuong.soNguyen.onNext(8) soAm.soNguyen.onNext(-3)

Kết quả:

1
2
3
4
Lỗi phát sinh: anError
-1
-2
-3

Tham khảo: https://fxstudio.dev/rxswift-transforming-operators/

Bình luận

Bài viết tương tự

- vừa được xem lúc

2 Cách để Triển Khai MVVM Trong Dự Án IOS

MVVM không nhất thiết phải bind cùng RxSwift, nhưng nó sẽ tốt hơn, vậy tại sao . MVVM Cùng Swift. Để thực hiện hai cách ràng buộc mà không phụ thuộc, chúng ta cần tạo Observable của riêng chúng ta. Đây là đoạn code :.

0 0 84

- vừa được xem lúc

Refresh token và retry request sử dụng RxSwift

Đặt vấn đề. Trong các dự án iOS sử dụng authenticator, việc đăng nhập thường hay được sử dụng bằng access token sau khi đã đăng nhập thành công bằng tài khoản và mật khẩu.

0 0 39

- vừa được xem lúc

RxSwift: KVO - Key Value Observing

I. Khái niệm:.

0 0 46

- vừa được xem lúc

Observable là gì? Cách tạo ra Observable

RxSwift là một thư viện cho phép chúng ta sử dụng Swift một cách khác nhau. Với thư viện này, lập trình bất đồng bộ trở nên dễ thực hiện hơn và dễ đọc hơn.

0 0 83

- vừa được xem lúc

Bài 3. RxSwift – DisposeBag

1.DisposeBag và vấn đề. . Nếu Observable không kết thúc thì sao nào.

0 0 10

- vừa được xem lúc

Bài 2. RxSwift – Observables

1. Observables. Đây là phần trung tâm của RxSwift. Observable chính là trái tim của cả hệ thống.

0 0 15