0

RxSwift: Transforming Operators

Chuyển đổi các Element

Thêm ví dụ mới này vào playground:

example(of: "toArray") {

  let disposeBag = DisposeBag()

  // 1
  Observable.of("A", "B", "C")
    // 2
    .toArray()
    .subscribe(onNext: {
      print($0)
    })
    .addDisposableTo(disposeBag)
}

Đây là những gì bạn vừa làm:

  1. Tạo ra một Observable của các chữ cái.
  2. Sử dụng toArray để biến đổi các phần tử trong một mảng.

Một mảng các chữ cái được in ra.

--- Example of: toArray ---
["A", "B", "C"]

Toán tử map của RxSwift hoạt động giống như map chuẩn của Swift, ngoại trừ nó hoạt động trên observables. Trong sơ đồ bên dưới, map có một closure mà tích của mỗi phần từ bằng 2.

Thêm đoạn ví dụ sau vào playground:

example(of: "map") {

  let disposeBag = DisposeBag()

  // 1
  let formatter = NumberFormatter()
  formatter.numberStyle = .spellOut

  // 2
  Observable<NSNumber>.of(123, 4, 56)
    // 3
    .map {
      formatter.string(from: $0) ?? ""
    }
    .subscribe(onNext: {
      print($0)
    })
    .addDisposableTo(disposeBag)
}

Đây là cách play-by-play:

  1. Bạn tạo ra một định dạng số để đánh vần từng số.
  2. Bạn tạo ra một observable của NSNumbers (để bạn không phải chuyển đổi số nguyên khi sử dụng các định dạng tiếp theo).
  3. Bạn sử dụng map để biến đổi các số thành các string và sẽ trả về rỗng nếu số phần tử đó nil.

Chương 5 sẽ bao gồm các operator filter, một số trong số chúng có biến thể withIndex. Cũng đúng với các operator chuyển đổi. Trong biểu đồ bên dưới, mapWithIndex sẽ chuyển đổi các element bằng cách nhân nó với 2 nếu element đó lớn hơn 1, nếu không nó sẽ giữ nguyên giá trị element đó, vì vậy chỉ có element thứ 3 được chuyển đổi.

Bây giờ thêm ví dụ mới này vào playground để thực hiện những gì đã nói ở trên:

example(of: "mapWithIndex") {

  let disposeBag = DisposeBag()

  // 1
  Observable.of(1, 2, 3, 4, 5, 6)
    // 2
    .mapWithIndex { integer, index in
      index > 2 ? integer * 2 : integer
    }
    .subscribe(onNext: {
      print($0)
    })
    .addDisposableTo(disposeBag)
}

Khá đơn giản:

  1. Bạn tạo ra một observable của các số nguyên.
  2. Bạn sử dụng mapWithIndex và nếu chỉ số của phần tử lớn hơn 2 sẽ nhân nó với 2 và trả về nó, ngược lại sẽ giữ nguyên giá trị và trả về.

Chỉ có phần tử thứ 4 trở đi mới được chuyển đổi và gửi đến các subscriber để in ra.

--- Example of: mapWithIndex ---
1
2
3
8
10
12

Chuyển đổi các observable bên trong

Thêm mã sau vào playground của bạn mà bạn sẽ sử dụng trong các ví dụ sắp tới:

struct Student {
    
  var score: Variable<Int>
}

Student là cấu trúc có một thuộc tính score là một Variable. RxSwift bao gồm một vài operator trong flatMap cho phép bạn tiếp cận với các giá trị có thể observable và làm việc với các giá trị đó. Bạn sẽ học cách sử dụng hai loại phổ biến nhất ở đây.

Thêm ví dụ này vào playground, thực hành với flatMap và thực sự thấy làm thế nào để sử dụng nó:

example(of: "flatMap") {

  let disposeBag = DisposeBag()

  // 1
  let ryan = Student(score: Variable(80))
  let charlotte = Student(score: Variable(90))

  // 2
  let student = PublishSubject<Student>()

  // 3
  student.asObservable()
    .flatMap {
      $0.score.asObservable()
    }
    // 4
    .subscribe(onNext: {
      print($0)
    })
    .addDisposableTo(disposeBag)
}
  1. Bạn tạo hai trường hợp của Student, ryan và charlotte.
  2. Bạn tạo ra một Subject của kiểu Student.
  3. Bạn sử dụng FlatMap để truy cập vào subject của Student và truy cập điểm số của nó, đó là một Variable, do đó bạn gọi asObservable() trên đó. Bạn không sửa đổi điểm số bằng bất kỳ cách nào. Chỉ cần pass qua nó.
  4. Bạn in ra các thành phần sự kiện tương ứng trong subscribe.

Sẽ không có gì được in. Thêm mã này vào ví dụ:

student.onNext(ryan)

Kết quả là điểm của ryan được in ra.

--- Example of: flatMap ---
80

Bây giờ thay đổi điểm của ryan bằng cách thêm mã này vào ví dụ:

ryan.score.value = 85

Điểm mới của ryan được in.

85

Tiếp theo, thêm một cá thể Student khác (charlotte) vào subject bằng cách thêm mã này:

student.onNext(charlotte)

flatMap thực hiện điều của nó và số điểm của charlotte được in

90

Điều này là do flatMap theo kịp mỗi và mọi quan sát được nó tạo ra, mỗi phần tử được thêm vào subject có thể quan sát được. Bây giờ thay đổi điểm số của charlotte bằng cách thêm mã sau, chỉ để xác minh rằng cả hai đều có thể quan sát đang được theo dõi và thay đổi:

charlotte.score.value = 100

Chắc chắn, điểm số mới của cô ấy được in ra.

100

Tóm lại, flatMap giữ các thay đổi từ mỗi điểm quan sát được. Sẽ có những lúc bạn muốn hành vi này. Và sẽ có những lúc bạn chỉ muốn theo kịp với các element mới nhất trong subject có thể quan sát được.

flatMapLatest

flatMapLatest thực sự là một sự kết hợp của hai operator, map và switchLatest. Bạn sẽ tìm hiểu về switchLatest trong chương "Combining Operators" của cuốn sách, nhưng bạn đang tìm kiếm ở đây. switchLatest sẽ tạo ra các giá trị từ gần đây nhất có thể quan sát, và bỏ đăng ký từ các quan sát trước đây.

Vì vậy, flatMapLatest "Dự án mỗi phần tử của một chuỗi có thể quan sát được vào một dãy các chuỗi quan sát được mới và sau đó biến đổi một dãy các chuỗi quan sát có thể quan sát được thành một chuỗi có thể quan sát được chỉ tạo ra các giá trị từ trình tự quan sát gần đây nhất." ! Hãy xem sơ đồ của flatMapLatest.

Tóm lại nhìn thì khá là rắc rối nên chúng ta sẽ đi vào thực hành luôn. Thêm ví dụ sau vào playground của bạn, đây là bản copy/paste của ví dụ trước, ngoại trừ việc thay đổi FlatMap thành flatMapLatest:

example(of: "flatMapLatest") {

  let disposeBag = DisposeBag()

  let ryan = Student(score: Variable(80))
  let charlotte = Student(score: Variable(90))

  let student = PublishSubject<Student>()

  student.asObservable()
    .flatMapLatest {
      $0.score.asObservable()
    }
    .subscribe(onNext: {
      print($0)
    })
    .addDisposableTo(disposeBag)

  student.onNext(ryan)

  ryan.score.value = 85

  student.onNext(charlotte)

  // 1
  ryan.score.value = 95

  charlotte.score.value = 100
}

Chỉ có một điều để chỉ ra ở đây là khác nhau từ ví dụ trước đó của flatMap:

  1. Thay đổi điểm số của ryan ở đây sẽ không có hiệu lực. Nó sẽ không được in ra. Điều này là do flatMapLatest đã chuyển sang chế độ có thể quan sát gần đây nhất, cho charlotte.
--- Example of: flatMapLatest ---
80
85
90
100

Vì vậy, bạn có thể tự hỏi khi nào bạn sử dụng FlatMap cho flatMapLatest? Có lẽ trường hợp sử dụng phổ biến nhất là sử dụng flatMapLatest với hoạt động mạng. Bạn sẽ đi qua các ví dụ này sau trong cuốn sách, nhưng đối với một ví dụ đơn giản, hãy tưởng tượng rằng bạn đang thực hiện một tìm kiếm kiểu trước. Khi người dùng nhập từng chữ cái, s, w, i, f, t, bạn sẽ muốn thực hiện một tìm kiếm mới và bỏ qua kết quả từ một cái trước đó. flatMapLatest là cách bạn làm điều đó.

Nguồn: www.raywenderlich.com


All rights reserved

Viblo
Hãy đăng ký một tài khoản Viblo để nhận được nhiều bài viết thú vị hơn.
Đăng kí