RxSwift 之變換操作

2021-09-11 14:09:14 字數 4597 閱讀 2392

可能剛開始接觸 rxswift 時候,你會覺得 rxswift 非常難懂也不容易學。其實學習每一門新知識或多或少都會出現這種情況。不過我相信認知讀了前幾篇文章後,你會深感 rxswift 的強大。它在簡化**量的同時也讓整個程式的邏輯變的更為清晰。

這篇文章將會繼續介紹另一組非常重要的 rxswift 操作:transforming operator。通過這組操作我們可以在觀察者使用之前對資料進行一次預處理。

可觀察物件每次都只會傳送乙個資料,但是有時候訂閱者卻希望獲得是一組資料。其中最典型的應用場景就是 uitableview 這類資料來源為陣列的檢視。rxswift 中實現此功能最簡單的方法就是通過 toarray 操作。如下圖所示, toarray 操作能將可觀察示例傳送的資料組合為陣列物件從而簡化訂閱者的後續處理。

01

let strikes = publishsubject

()let disposebag = disposebag()

strikes

.toarray()

.subscribe(onnext: )

.adddisposableto(disposebag)

strikes.onnext("1")

strikes.onnext("2")

strikes.onnext("3")

strikes.oncompleted()複製**

除了將元素轉化為陣列之外,我們還可以使用函式式程式設計方法對每個資料進行變換操作。其中最常見的就是 map 以及變種 mapwithindex 。這裡我們先來看 map 操作的演示示例:

02

通過 map 我們將內部資料數值成功擴大了一倍,而圖示對應**為:

let strikes = publishsubject

()let disposebag = disposebag()

strikes

.map

.subscribe(onnext: )

.adddisposableto(disposebag)

strikes.onnext(1)

strikes.onnext(2)

strikes.onnext(3)

strikes.oncompleted()複製**

與之前介紹的其它變種操作一樣, mapwithindex 也只是在 map 基礎上新增了索引引數。下圖中演示了只對索引大於 1 的 double 操作:

03

對應**如下:

let strikes = publishsubject

()let disposebag = disposebag()

strikes

.mapwithindex

.subscribe(onnext: )

.adddisposableto(disposebag)

strikes.onnext(1)

strikes.onnext(2)

strikes.onnext(3)

strikes.oncompleted()複製**

並不是每個型別物件都會被設計為可觀察型別,有時候可能只是物件例項的某個屬性是可觀察型別。例如,下面的student型別:

struct

student

複製**

student型別本身並不是可觀察型別,但是屬性 score 卻屬於 variable 型別。對於這種情況我們可以通過 flatmap 系列操作對 score 進行觀察從而將student型別例項轉化為某種意義上的可觀察型別。

第乙個基本操作就是 flatmap,在 swift 標準庫里該操作用於函式式程式設計,它能將那些多維集合型別轉換為一維集合型別。而 flatmap 在 rxswift 中的操作過程如下圖:

04

圖中第一行 o1、o2、o3 表示三個型別例項,然後該型別例項有乙個可觀察屬性 value 。通過 flatmap 操作我們將其轉成了最後一行的可觀察序列。剛開始 o1、o2、o3 的 value 值分別為 1、2、3,然後經過 flatmap 操作轉化為了 10、20、30 。然後我們修改 o1、o2 的 value 為 4 和 5,此時 flatmap 會獲得通知並生成數值 40、50。

將這段操作應用到student型別上的**:

let disposebag = disposebag()

// 1

let o1 = student(score: variable(1))

let o2 = student(score: variable(2))

let o3 = student(score: variable(3))

// 2

let student = publishsubject

()// 3

student.asobservable()

.flatmap

.map

.subscribe(onnext: )

.adddisposableto(disposebag)

student.onnext(o1)

student.onnext(o2)

student.onnext(o3)

o1.score.value = 4

o2.score.value = 5

student.oncompleted()複製**

與之前一樣 flatmap 也有乙個名為 flatmapwithindex 的變種操作,讀者可以自己查閱文件。接下來,我會介紹 flatmap 系列的另兩個操作 flatmaplatest 和 flatmapfirst。

與 flatmap 不同,flatmaplatest 只會關注最新的可觀察物件,而前者則對所有的可觀察物件作出響應。你可以將 flatmaplatest 看作是 map 以及 switchlatest 的組合操作。下圖展示了 flatmaplatest 的具體操作:

05

可以看到 flatmaplatest 並不會和之前一樣在最下面一行產生 30、50 。因為 o1 數值設為 3 的時候,最新的可觀察物件是 o2 ,同理設定 o2 數值時最新物件已經是 o3 了,而 flatmaplatest 對於這些行為不會做出任何響應。

操作過程的對應**如下:

let disposebag = disposebag()

// 1

let o1 = student(score: variable(1))

let o2 = student(score: variable(2))

let o3 = student(score: variable(4))

// 2

let student = publishsubject

()// 3

student.asobservable()

.flatmaplatest

.map

.subscribe(onnext: )

.adddisposableto(disposebag)

student.onnext(o1)

student.onnext(o2)

o1.score.value = 3

student.onnext(o3)

o2.score.value = 5

o3.score.value = 6

student.oncompleted()複製**

而 flatmapfirst 操作相對來說更簡單,它只會對第乙個可觀察物件做出響應。也就是說,在與上例一樣的情形下它只會對 o1 做出響應。

let disposebag = disposebag()

// 1

let o1 = student(score: variable(1))

let o2 = student(score: variable(2))

let o3 = student(score: variable(4))

// 2

let student = publishsubject

()// 3

student.asobservable()

.flatmaplatest

.map

.subscribe(onnext: )

.adddisposableto(disposebag)

student.onnext(o1)

student.onnext(o2)

o1.score.value = 3

student.onnext(o3)

o2.score.value = 5

o3.score.value = 6

student.oncompleted()

/* 列印結果

1030

*/複製**

##總結

本文簡單了介紹了 rxswift 中一些常見的變換操作。雖然文中的**和示例有些簡單,但這並不影響理解。

原文位址

Rxjava的學習之變換操作符 scan

連續地對資料序列的每一項應用乙個函式,然後連續發射結果 scan操作符對原始observable發射的第一項資料應用乙個函式,然後將那個函式的結果作為自己的第一項資料發射。它將函式的結果同第二項資料一起填充給這個函式來產生它自己的第二項資料。它持續進行這個過程來產生剩餘的資料序列。這個操作符在某些情...

RxSwift教程 16 除錯操作

1 基本介紹 2 使用樣例12 3456 7letdisposebag disposebag observable.of 2 3 startwith 1 debug subscribe onnext disposed by disposebag 執行結果如下 3 debug 方法還可以傳入標記引數,...

小白學opengl之變換函式心得

include include include include include using namespace std static int y 0,d 0 void init void void display void void reshape int w,int h void keyboard...