SwiftUI 與 Combine(二)

操作符

本文將介紹Combine中的各類運算符蓝角,這些運算符不要求你能夠立即掌握,只要記得有某種運算符具有某種作用饭冬,在實際編程中可以將本文作為文檔查詢(ps:作者在使用RXSwift時也會經(jīng)常查詢某些不常用的操作符)
正如Swift標準庫中對數(shù)組的操作符(map使鹅、filter、zip...)一樣昌抠,publisher也有著變形患朱、篩選、鏈接等等操作符

collect

本操作符將單個元素緩存到集合中(可以指定緩存?zhèn)€數(shù)炊苫,滿足個數(shù)或者收到完成事件后)裁厅,然后發(fā)送集合


15785495862104.jpg
var subscriptions = Set<AnyCancellable>()
var subscriptions = Set<AnyCancellable>()
example(of: "collect") {
    ["A", "B", "C", "D", "E"].publisher
//        .collect()
//        .collect(2)
        .sink(receiveCompletion: { print($0) },
              receiveValue: { print($0) })
        .store(in: &subscriptions)
}
/* 輸出
——— Example of: collect ———
A
B
C
D
E
finished

// 打開.collect()注釋
——— Example of: collect ———
["A", "B", "C", "D", "E"]
finished

// 注釋掉.collect()打開.collect(2)注釋
——— Example of: collect ———
["A", "B"]
["C", "D"]
["E"]
finished
*/

使用.collect和其他沒有指定個數(shù)或緩存大小的操作符時冰沙,注意他們講使用沒有內(nèi)存大小限制的緩存區(qū)存儲收到的元素。注意內(nèi)存溢出

map(_:)

和Swift標準庫中集合的Map類似姐直,使用函數(shù)倦淀、閉包、或者keyPath來轉變值

/// 將數(shù)字轉換成對應的ASCll值的字符声畏,無法轉換時返回空字符
func numToString(num: Int) -> String {
    .init(Character(Unicode.Scalar(num) ?? "\0"))
}
example(of: "map") {
    (65...67)
        .publisher
        .map(numToString(num:))
        .print()
        .map(\.localizedLowercase)
        .sink(receiveCompletion: { print($0) }, receiveValue: { print($0) })
        .store(in: &subscriptions)
}
/* 輸出
——— Example of: map ———
receive subscription: (["A", "B", "C", "D", "E"])
request unlimited
receive value: (A)
a
receive value: (B)
b
receive value: (C)
c
receive finished
finished
*/

print

打印接受到的值或者完成事件,通常用在調(diào)試的時候

tryMap

包括map在內(nèi)的幾個操作符都有一個對應的try操作符姻成,該操作符將接受可能引發(fā)錯誤的閉包插龄。如果有錯誤拋出,它將發(fā)送錯誤完成事件

example(of: "tryMap") {
    let publisher = PassthroughSubject<String, Never>()

    publisher
        .tryMap { try JSONSerialization.jsonObject(with: $0.data(using: .utf8)!, options: .allowFragments) }
        .sink(receiveCompletion: { print($0) },
              receiveValue: { print($0) })
        .store(in: &subscriptions)

    publisher.send(#"{"name":"DKJone"}"#)
    publisher.send("not a JSON")
}

/* 輸出
——— Example of: tryMap ———
{
    name = DKJone;
}
failure(Error Domain=NSCocoaErrorDomain Code=3840 ...."})
*/

此處使用的#""#為原始字符串更多內(nèi)容查看Swift5新特性 & XCode 10.2更新

flatMap

在swift標準庫中FlatMap用來使多為數(shù)組扁平化為一位數(shù)組科展,并且在swift4.1中被重命名為Swift 4.1中被重命名為compactMap均牢,在Combine中flatmap的作用稍微有點不同。
flatmap作用是在publisher內(nèi)部仍然包含publisher時可以將事件扁平化才睹,具體查看以下代碼:

example(of: "flatMap") {
    // 1 定義三個人用于聊天
    let 小明 = Chatter(name: "小明", message: "小明: 鄙人王小明!")
    let 老王 = Chatter(name: "老王", message: "老王: 我就是隔壁老王!")
    let 于大爺 = Chatter(name: "于大爺", message: "燙頭去")

    // 2 j可以獲取當前值的Publishers初始值是小明
    let chat = CurrentValueSubject<Chatter, Never>(小明)

//    chat
//        .flatMap(maxPublishers: .max(2)) { $0.message }
//        .sink(receiveValue: { print($0) })
//        .store(in: &subscriptions)

    chat.sink{ print($0.message.value)}

    小明.message.value = "小明: 馬冬梅在家嗎徘跪?"
    chat.value = 老王
    老王.message.value = "老王: 什么冬梅?"
    小明.message.value = "小明: 馬冬梅袄湃痢垮庐!"
    chat.value = 于大爺
    老王.message.value = "老王: 馬東什么?"
}

/* 輸出
——— Example of: flatMap ———
小明: 鄙人王小明!
老王: 我就是隔壁老王!
燙頭去

// 注釋chat.sink{ print($0.message.value)}打開上放訂閱的注釋輸出
——— Example of: flatMap ———
小明: 鄙人王小明!
小明: 馬冬梅在家嗎坞琴?
老王: 我就是隔壁老王!
老王: 什么冬梅哨查?
小明: 馬冬梅啊剧辐!
老王: 馬東什么寒亥?
*/

在一開始我們使用chat.sink{ print($0.message.value)}訂閱事輸出只有三句話,這是因為我們只對chat進行了訂閱荧关。當具體的Chatter的message變化時溉奕,我們并不能訂閱到事件。那我想訂閱全部的談話事件怎么辦呢忍啤?flatMap正是為此而生的加勤,當我們改成flatmap的訂閱后可以輸出所有publisher的事件,包括publisher的值內(nèi)部的publisher發(fā)出的事件檀轨。上面我們也提到胸竞,map操作會緩存publisher,為了防止我們緩存太多的publisher我們可以在flatmap事指定緩存的publisher個數(shù)(maxPublishers: .max(2))参萄,所以于老師并沒有被沒緩存卫枝,也就沒有發(fā)出于老師說話的事件。如果未指定個數(shù)讹挎,則maxPublishers默認為.unlimited校赤。

15785615311395.jpg

compactMap

和swift標準庫中的數(shù)組操作符一樣吆玖,如果你在轉換時不需要轉換失敗的nil值,你使用此方法將的到一個沒有可選值的序列

example(of: "compactMap") {
    let strings = ["a", "1.24", "3", "def", "45", "0.23"].publisher

    // 2
    strings
        .compactMap { Float($0) }
        .sink(receiveValue: { print($0)})
        .store(in: &subscriptions)
}
/* 輸出
——— Example of: compactMap ———
1.24
3.0
45.0
0.23
*/

replaceNil(with:)

對的它的作用和方法名一樣直白马篮,就是在遇到可選值為空時用默認值替換空值,原始的序列也變成一個非空序列

example(of: "replaceNil") {
  ["A", nil, "C"].publisher
    .replaceNil(with: "-")
    .map { $0! }
    .sink(receiveValue: { print($0) }) 
    .store(in: &subscriptions)
}
/* 輸出
——— Example of: replaceNil ———
A
-
C
*/

replaceEmpty(with:)

替換空序列

example(of: "replaceEmpty(with:)") {
  let empty = Empty<Int, Never>()
  empty
    .replaceEmpty(with: 1)
    .sink(receiveCompletion: { print($0) },
          receiveValue: { print($0) })
    .store(in: &subscriptions)
}

Empty:創(chuàng)建一個只發(fā)出完成事件的序列

scan(::)

掃描之前的序列中所有元素沾乘,運用函數(shù)計算新值,接收一個初始值和每次接受到新元素的函數(shù)

example(of: "scan") {
    // 1 一共進了10個球 每個球進球得分隨機1~3分浑测,每次進球后打印當前總分
    let score = (1..<10).compactMap { _ in (1...3).randomElement() }
    score
        .publisher
        .print()
        .scan(0, +)
        .sink(receiveValue: { print($0) })
        .store(in: &subscriptions)
}
/* 輸出
——— Example of: scan ———
receive subscription: ([1, 1, 2, 1, 1, 2, 3, 1, 3])
request unlimited
receive value: (1)
1
receive value: (1)
2
receive value: (2)
4
receive value: (1)
5
receive value: (1)
6
receive value: (2)
8
receive value: (3)
11
receive value: (1)
12
receive value: (3)
15
receive finished
*/

注意.scan(0, +)這里的 + 是一個函數(shù),你可以在Xcode點擊查看其聲明
public static func + (lhs: Int, rhs: Int) -> Int

tryScan

作為一名有經(jīng)驗的程序員翅阵,你應該能自己聯(lián)想到他的功能,對就是你想的那樣迁央。

在后面的操作符中如果沒有特殊功能將不再單獨介紹相關的try運算符掷匠,但我會告訴你它的存在

Filtering

和標準庫的Array的方法一樣,該方法也是接受一個返回Bool值的函數(shù)過濾元素岖圈,返回false的值將被過濾掉

example(of: "filter") {
    let numbers = [(1,2),(2,4),(3,1),(6,2),(1,0)].publisher

    // 過濾掉第一個值小于第二個值的元祖
    numbers
        .filter( > )
        .sink(receiveValue: { print("\($0) 大于 \($1)") })
        .store(in: &subscriptions)
}
/* 輸出
——— Example of: filter ———
3 大于 1
6 大于 2
1 大于 0
*/

注意此處的 >是一個函數(shù)讹语,這里的參數(shù)可以是函數(shù)(或者閉包-匿名函數(shù))
public static func > (lhs: Int, rhs: Int) -> Bool

removeDuplicates

過濾掉連續(xù)的重復值


15828721202656.jpg
example(of: "removeDuplicates") {
    // 1
    let userInput = ["aaa", "aaa", "bbbb", "ccc", "bbbb"].publisher

    // 2
    userInput
        .removeDuplicates()
        .sink(receiveValue: { print($0) })
        .store(in: &subscriptions)
}
/* 輸出
——— Example of: removeDuplicates ———
aaa
bbbb
ccc
bbbb
*/

ignoreOutput

忽略發(fā)送的值,如果有的時候你只在乎publisher有沒有完成發(fā)送二不關心他具體發(fā)送了那些值蜂科,可已使用ignoreOutput顽决,使用后將只會訂閱到完成事件(錯誤完成或者正常結束)

example(of: "ignoreOutput") {
    // 1
    let numbers = (1...10_000).publisher
    // 2
    numbers
        .ignoreOutput()
        .sink(receiveCompletion: { print("Completed with: \($0)") },
              receiveValue: { print($0) })
        .store(in: &subscriptions)
}

/* 輸出
——— Example of: ignoreOutput ———
Completed with: finished
*/

compactMap

轉換時忽略掉無法轉換的值,和標準庫中的Array 的同名方法類似

example(of: "compactMap") {
    let strings = ["http://www.baidu.com", "dkjone://happy.lv", "哈利路亞", "", "https://127.0.0.1"].publisher

    strings
        .compactMap(URL.init(string:))
        .sink(receiveValue: { print($0.absoluteString) })
        .store(in: &subscriptions)
}

/* 輸出
——— Example of: compactMap ———
http://www.baidu.com
dkjone://happy.lv
https://127.0.0.1
*/

first(where:)

找到序列中的第一個滿足條件的值然后發(fā)出导匣,并且發(fā)送完成事件才菠,取消上游的publishers繼續(xù)向其發(fā)送值

example(of: "first(where:)") {
    let numbers = (1...9).publisher
    numbers
        .print("numbers")
        .first(where: { $0 % 2 == 0 })
        .sink(receiveCompletion: { print("Completed with: \($0)") },
              receiveValue: { print($0) })
        .store(in: &subscriptions)
}
/* 輸出
——— Example of: first(where:) ———
numbers: receive subscription: (1...9)
numbers: request unlimited
numbers: receive value: (1)
numbers: receive value: (2)
numbers: receive cancel
2
Completed with: finished
*/

last(where:)

與first(where:)相反,此運算符是貪婪的逐抑,因為它必須等待所有值發(fā)出鸠儿,才能知道是否找到匹配的值。因此厕氨,上游必須是一個已經(jīng)經(jīng)完成的publisher

example(of: "last(where:)") {
    let numbers = PassthroughSubject<Int, Never>()
    numbers
        .last(where: { $0 % 2 == 0 })
        .sink(receiveCompletion: { print("Completed with: \($0)") },
              receiveValue: { print($0) })
        .store(in: &subscriptions)

    numbers.send(1)
    numbers.send(2)
    numbers.send(3)
    numbers.send(4)
    numbers.send(5)
    numbers.send(completion: .finished)
}
/* 輸出
——— Example of: last(where:) ———
4
Completed with: finished
*/

dropFirst

忽略指定個數(shù)的值

example(of: "dropFirst") {
    let numbers = (1...10).publisher
    numbers
        .dropFirst(8)
        .sink(receiveValue: { print($0) })
        .store(in: &subscriptions)
}
/* 輸出
——— Example of: dropFirst ———
9
10
*/

drop(while:)

忽略序列中的值直到滿足條件時进每。

 example(of: "drop(while:)") {
    let numbers = (1...10).publisher
    numbers
        .drop(while: { $0 % 5 != 0 })
        .sink(receiveValue: { print($0) })
        .store(in: &subscriptions)
}

/* 輸出
——— Example of: drop(while:) ———
5
6
7
*/

drop(untilOutputFrom:)

忽略序列中對的值直到另一個序列開始發(fā)送值

 example(of: "drop(untilOutputFrom:)") {
    let isReady = PassthroughSubject<Void, Never>()
    let taps = PassthroughSubject<Int, Never>()

    taps
        .drop(untilOutputFrom: isReady)
        .sink(receiveValue: {
            print($0)
        })
        .store(in: &subscriptions)

    (1...5).forEach { n in
        taps.send(n)
        if n == 3 {
            isReady.send()
        }
    }
}
/* 輸出
——— Example of: drop(untilOutputFrom:) ———
4
5
*/

prefix

獲取序列中指定個數(shù)的值,然后發(fā)出完成事件

 example(of: "prefix") {
    let numbers = (1...10).publisher
    numbers
        .prefix(2)
        .sink(receiveCompletion: { print("Completed with: \($0)") },
              receiveValue: { print($0) })
        .store(in: &subscriptions)
}
/* 輸出
——— Example of: prefix ———
1
2
Completed with: finished
*/

prefix(while:)

獲取序列中的值直到滿足給定的條件命斧,然后發(fā)出完成事件田晚,與 drop(while:)相反


15828722470169.jpg

prefix(untilOutputFrom:)

獲取序列中的值直到給定的序列發(fā)出值,然后發(fā)出完成事件国葬,與 drop(untilOutputFrom:)相反


15828722334301.jpg

prepend

在原始的publisher序列前面追加給定的值贤徒,值的類型必須與原始序列類型一致


15828726074065.jpg
 example(of: "prepend(Output...)") {
  let publisher = [3, 4].publisher
  publisher
    .prepend(1, 2)
    .sink(receiveValue: { print($0) })
    .store(in: &subscriptions)
}
/* 輸出
——— Example of: prepend(Output...) ———
1
2
3
4
*/

prepend(Sequence)

在原始的publisher序列前面追加給定序列中的所有值,值的類型必須與原始序列類型一致

prepend(Publisher)

在原始的publisher序列前面追加給定publisher 序列中的所有值汇四,值的類型必須與原始序列類型一致接奈,如果追加的publisher是一個未完成的序列,會等新追加序列發(fā)送完成事件再發(fā)送原始序列中的值

example(of: "prepend(Publisher) #2") {
  let publisher1 = [3, 4].publisher
  let publisher2 = PassthroughSubject<Int, Never>()

  publisher1
    .prepend(publisher2)
    .sink(receiveValue: { print($0) })
    .store(in: &subscriptions)

  publisher2.send(1)
  publisher2.send(2)
//  publisher2.send(completion: .finished)
}
/* 輸出
——— Example of: prepend(Publisher) ———
1
2

//打開最后一行注釋后輸出
——— Example of: prepend(Publisher) ———
1
2
3
4
*/

append()

與prepend() 類似通孽,只是位置改為在原始序列末尾追加

append(Sequence)

與prepend(Sequence) 類似序宦,只是位置改為在原始序列末尾追加

15828732022683.jpg
 example(of: "append(Output...)") {
    let publisher = [1].publisher

    publisher
        .append(2, 3)
        .append(4)
        .sink(receiveValue: { print($0) })
        .store(in: &subscriptions)
}
/* 輸出
——— Example of: append(Output...) ———
1
2
3
4
*/

append(Publisher)

與prepend(Publisher) 類似,只是位置改為在原始序列末尾追加

switchToLatest

從一個publiser切換到另一個背苦,這會停止接收之前publisher的值而改成接收新切換的publisher序列中的值


15828737758818.jpg
 example(of: "switchToLatest") {
    let publisher1 = PassthroughSubject<Int, Never>()
    let publisher2 = PassthroughSubject<Int, Never>()
    let publisher3 = PassthroughSubject<Int, Never>()

    let publishers = PassthroughSubject<PassthroughSubject<Int, Never>, Never>()

    publishers
        .switchToLatest()
        .sink(receiveCompletion: { _ in print("Completed!") },
              receiveValue: { print($0) })
        .store(in: &subscriptions)

    publishers.send(publisher1)
    publisher1.send(1)
    publisher1.send(2)

    publishers.send(publisher2)
    publisher1.send(3)
    publisher2.send(4)
    publisher2.send(5)

    publishers.send(publisher3)
    publisher2.send(6)
    publisher3.send(7)
    publisher3.send(8)
    publisher3.send(9)

    publisher3.send(completion: .finished)
    publishers.send(completion: .finished)
}
/* 輸出
——— Example of: switchToLatest ———
1
2
4
5
7
8
9
Completed!
*/

merge(with:)

與RXSwift中的同名操作符效果一致互捌,將publishers中的值按時間順序合并成一個publisher潘明,值類型必須一致

image
example(of: "merge(with:)") {
    let publisher1 = PassthroughSubject<Int, Never>()
    let publisher2 = PassthroughSubject<Int, Never>()

    publisher1
        .merge(with: publisher2)
        .sink(receiveCompletion: { _ in print("Completed") },
              receiveValue: { print($0) })
        .store(in: &subscriptions)

    publisher1.send(1)
    publisher1.send(2)

    publisher2.send(3)

    publisher1.send(4)

    publisher2.send(5)

    publisher1.send(completion: .finished)
    publisher2.send(completion: .finished)
}

/* 輸出
——— Example of: merge(with:) ———
1
2
3
4
5
Completed
*/

combineLatest

與RXSwift中的同名操作符效果一致,當多個 publisher 中任何一個發(fā)出一個元素秕噪,就發(fā)出一個元素钳降。這個元素是由這些 publisher 中最新的元素組合起來的元組,各個publisher的值類型可以不一樣


15828766695342.jpg
example(of: "combineLatest") {
    let publisher1 = PassthroughSubject<Int, Never>()
    let publisher2 = PassthroughSubject<String, Never>()

    publisher1
        .combineLatest(publisher2)
        .sink(receiveCompletion: { _ in print("Completed") },
              receiveValue: { print("P1: \($0), P2: \($1)") })
        .store(in: &subscriptions)

    publisher1.send(1)
    publisher1.send(2)

    publisher2.send("a")
    publisher2.send("b")

    publisher1.send(3)

    publisher2.send("c")

    publisher1.send(completion: .finished)
    publisher2.send(completion: .finished)
}

/* 輸出
——— Example of: combineLatest ———
P1: 2, P2: a
P1: 2, P2: b
P1: 3, P2: b
P1: 3, P2: c
Completed
*/

zip

與swift標準庫和RXSwift的同名函數(shù)左營類似腌巾,在publisher相同索引處發(fā)出成對值的元組遂填。它等待每個publisher發(fā)出一個值,然后在所有publisher在當前索引處發(fā)出一個元素后發(fā)出一個值的元組澈蝙。這意味著城菊,如果zip兩個publisher,則每次兩個發(fā)布服務器都發(fā)出一個值時碉克,才會發(fā)出一個元組。


image
example(of: "zip") {
    let publisher1 = PassthroughSubject<Int, Never>()
    let publisher2 = PassthroughSubject<String, Never>()

    publisher1
        .zip(publisher2)
        .sink(receiveCompletion: { _ in print("Completed") },
              receiveValue: { print("P1: \($0), P2: \($1)") })
        .store(in: &subscriptions)

    publisher1.send(1)
    publisher1.send(2)

    publisher2.send("a")
    publisher2.send("b")

    publisher1.send(3)

    publisher2.send("c")
    publisher2.send("d")

    publisher1.send(completion: .finished)
    publisher2.send(completion: .finished)
}

/* 輸出
——— Example of: zip ———
P1: 1, P2: a
P1: 2, P2: b
P1: 3, P2: c
Completed
*/

delay(for)

延遲發(fā)出元素并齐,接受一個延遲時間參數(shù),以及要運行的線程

var subscriptions = Set<AnyCancellable>()
let start = Date()
let deltaFormatter: NumberFormatter = {
    let f = NumberFormatter()
    f.negativePrefix = ""
    f.minimumFractionDigits = 1
    f.maximumFractionDigits = 1
    return f
}()

/// 本頁代碼運行時初始化時間漏麦, 計算運行到固定行數(shù)時得到時間差
public var deltaTime: String {
    return deltaFormatter.string(for: Date().timeIntervalSince(start))!
}

example(of: "Delay") {
    let publisher = Timer.publish(every: 1, on: .main, in: .common).autoconnect()

    publisher.sink { date in
        print("origin:\t" + "\(deltaTime)\t" + date.description)
    }.store(in: &subscriptions)

    publisher.delay(for: .seconds(2), scheduler: DispatchQueue.main).sink { date in
        print("delay:\t" + "\(deltaTime)\t" + date.description)
    }.store(in: &subscriptions)
}

/* 輸出
——— Example of: Delay ———
origin: 1.1 2020-03-02 06:33:55 +0000
origin: 2.1 2020-03-02 06:33:56 +0000
origin: 3.1 2020-03-02 06:33:57 +0000
delay:  3.3 2020-03-02 06:33:55 +0000
origin: 4.1 2020-03-02 06:33:58 +0000
delay:  4.1 2020-03-02 06:33:56 +0000
...
*/

autoconnect() 在第一次訂閱時立即連接。

Collect

將原始序列中的元素組成集合發(fā)出况褪,可以接受的參數(shù)有集合個數(shù)撕贞、時間、個數(shù)或時間测垛。滿足參數(shù)條件就會發(fā)出集合捏膨,否則等待元素。(參數(shù)是時間和個數(shù)都設置時滿足任一就會發(fā)出)

example(of: "Collect") {
    let publisher = Timer.publish(every: 1, on: .main, in: .common).autoconnect()

    publisher.sink { date in
        print("origin:\t" + "\(deltaTime)\t" + date.description)
    }.store(in: &subscriptions)

    publisher.collect(.byTimeOrCount(DispatchQueue.main, .seconds(5), 3), options: .none) .sink { date in
        print("collect:\t" + "\(deltaTime)\t" + date.description)
    }.store(in: &subscriptions)
}
/* 輸出
——— Example of: Collect ———
origin: 1.1 2020-03-02 07:38:26 +0000
origin: 2.1 2020-03-02 07:38:27 +0000
origin: 3.1 2020-03-02 07:38:28 +0000
collect:    3.1 [2020-03-02 07:38:26 +0000, 2020-03-02 07:38:27 +0000, 2020-03-02 07:38:28 +0000]
origin: 4.1 2020-03-02 07:38:29 +0000
origin: 5.1 2020-03-02 07:38:30 +0000
collect:    5.1 [2020-03-02 07:38:29 +0000, 2020-03-02 07:38:30 +0000]
...
*/

Debounce(for)

與RXSwift同名操作符作用一致食侮,等待多長時間后沒有新值再發(fā)出該值号涯,忽略中間連續(xù)變化的值


debonce
example(of: "Debounce") {
   let publisher = PassthroughSubject<String,Never>()
   let typingHelloWorld: [(TimeInterval, String)] = [
      (0.0, "H"),
      (0.1, "He"),
      (0.2, "Hel"),
      (0.3, "Hell"),
      (0.5, "Hello"),
      (0.6, "Hello "),
      (2.0, "Hello W"),
      (2.1, "Hello Wo"),
      (2.2, "Hello Wor"),
      (2.4, "Hello Worl"),
      (2.5, "Hello World")
    ]
    //模擬輸入Hello Word
    typingHelloWorld.forEach { (delay,str) in
        DispatchQueue.main.asyncAfter(deadline: .now() + delay) {
            publisher.send(str)
        }
    }

    publisher.sink { data in
        print("origin:\t" + "\(deltaTime)\t" + data)
    }.store(in: &subscriptions)

    publisher.debounce(for: .seconds(1), scheduler: DispatchQueue.main).sink { data in
        print("debounce:\t" + "\(deltaTime)\t" + data)
    }.store(in: &subscriptions)
}

/* 輸出
——— Example of: Debounce ———
origin: 0.1 H
origin: 0.2 He
origin: 0.3 Hel
origin: 0.4 Hell
origin: 0.6 Hello
origin: 0.7 Hello 
debounce:   1.7 Hello 
origin: 2.2 Hello W
origin: 2.2 Hello Wo
origin: 2.5 Hello Wor
origin: 2.5 Hello Worl
origin: 2.8 Hello World
debounce:   3.8 Hello World
*/

throttle

與RXSwift同名操作符效果一致,在固定時間內(nèi)只發(fā)出一個值锯七,過濾掉其他值链快,你可以選擇最新的值或者第一個值發(fā)出

example(of: "throttle") {
   let publisher = PassthroughSubject<String,Never>()

    //模擬輸入Hello Word
    typingHelloWorld.forEach { (delay,str) in
        DispatchQueue.main.asyncAfter(deadline: .now() + delay) {
            publisher.send(str)
        }
    }

    publisher.sink { data in
        print("origin:\t" + "\(deltaTime)\t" + data)
    }.store(in: &subscriptions)

    publisher.throttle(for: .seconds(1), scheduler: DispatchQueue.main, latest: false).sink { data in
        print("throttle:\t" + "\(deltaTime)\t" + data)
    }.store(in: &subscriptions)
}
/* 輸出
——— Example of: throttle ———
origin: 0.1 H
throttle:   0.1 H
origin: 0.2 He
origin: 0.3 Hel
origin: 0.4 Hell
origin: 0.6 Hello
origin: 0.7 Hello 
throttle:   1.2 Hello 
origin: 2.2 Hello W
origin: 2.2 Hello Wo
throttle:   2.2 Hello Wo
origin: 2.5 Hello Wor
origin: 2.5 Hello Worl
origin: 2.8 Hello World
throttle:   3.5 Hello World
*/

Timeout

與RXSwift同名操作符一樣,超出給定的時間后發(fā)出結束事件眉尸,你可以給出自定義錯誤類型域蜗,這樣在超時后會發(fā)出錯誤完成事件


image

Measuring time

用于調(diào)試的操作符,計算兩次值發(fā)出的時間間隔噪猾,單位是納秒

min

發(fā)出原始序列中的最小值霉祸,然后發(fā)出完成事件。要求序列是已完成的序列否則會等待原始序列的完成事件袱蜡。

max

與min相反丝蹭,發(fā)出原始序列中的最大值,然后發(fā)出完成事件戒劫。要求序列是已完成的序列否則會等待原始序列的完成事件半夷。

first

發(fā)出原始序列中的第一個值婆廊,然后發(fā)出完成事件

last

與first相反,發(fā)出原始序列中的最后一個值巫橄,然后發(fā)出完成事件淘邻。要求序列是已完成的序列否則會等待原始序列的完成事件。

output(in:)

output(at:)發(fā)出指定位置的值湘换,output(in:)發(fā)出指定范圍內(nèi)的值

example(of: "output(in:)") {
  let publisher = ["A", "B", "C", "D", "E"].publisher
  publisher
    .print("publisher")
    .output(in: 1...3)
    .sink(receiveCompletion: { print($0) },
          receiveValue: { print("Value in range: \($0)") })
    .store(in: &subscriptions)
}
/*輸出
——— Example of: output(in:) ———
publisher: receive subscription: (["A", "B", "C", "D", "E"])
publisher: request unlimited
publisher: receive value: (A)
publisher: request max: (1) (synchronous)
publisher: receive value: (B)
Value in range: B
publisher: receive value: (C)
Value in range: C
publisher: receive value: (D)
Value in range: D
publisher: receive cancel
finished
*/

count

記錄原始序列發(fā)出值的個數(shù)宾舅,并發(fā)出

contains

原始publisher發(fā)出指定值,則contains運算符將發(fā)出true并取消訂閱彩倚;如果原始publisher已完成且發(fā)出的值均不等于指定值筹我,則發(fā)出false

reduce

與標準庫函數(shù)類似,在原始publisher完成時發(fā)出累計計算的到的值


15832015826163.jpg
最后編輯于
?著作權歸作者所有,轉載或內(nèi)容合作請聯(lián)系作者
  • 序言:七十年代末帆离,一起剝皮案震驚了整個濱河市蔬蕊,隨后出現(xiàn)的幾起案子,更是在濱河造成了極大的恐慌哥谷,老刑警劉巖岸夯,帶你破解...
    沈念sama閱讀 216,470評論 6 501
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件,死亡現(xiàn)場離奇詭異们妥,居然都是意外死亡猜扮,警方通過查閱死者的電腦和手機,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 92,393評論 3 392
  • 文/潘曉璐 我一進店門监婶,熙熙樓的掌柜王于貴愁眉苦臉地迎上來旅赢,“玉大人,你說我怎么就攤上這事惑惶≈笈危” “怎么了?”我有些...
    開封第一講書人閱讀 162,577評論 0 353
  • 文/不壞的土叔 我叫張陵集惋,是天一觀的道長孕似。 經(jīng)常有香客問我,道長刮刑,這世上最難降的妖魔是什么喉祭? 我笑而不...
    開封第一講書人閱讀 58,176評論 1 292
  • 正文 為了忘掉前任,我火速辦了婚禮雷绢,結果婚禮上泛烙,老公的妹妹穿的比我還像新娘。我一直安慰自己翘紊,他們只是感情好蔽氨,可當我...
    茶點故事閱讀 67,189評論 6 388
  • 文/花漫 我一把揭開白布。 她就那樣靜靜地躺著,像睡著了一般鹉究。 火紅的嫁衣襯著肌膚如雪宇立。 梳的紋絲不亂的頭發(fā)上,一...
    開封第一講書人閱讀 51,155評論 1 299
  • 那天自赔,我揣著相機與錄音妈嘹,去河邊找鬼。 笑死绍妨,一個胖子當著我的面吹牛润脸,可吹牛的內(nèi)容都是我干的。 我是一名探鬼主播他去,決...
    沈念sama閱讀 40,041評論 3 418
  • 文/蒼蘭香墨 我猛地睜開眼毙驯,長吁一口氣:“原來是場噩夢啊……” “哼!你這毒婦竟也來了灾测?” 一聲冷哼從身側響起爆价,我...
    開封第一講書人閱讀 38,903評論 0 274
  • 序言:老撾萬榮一對情侶失蹤,失蹤者是張志新(化名)和其女友劉穎媳搪,沒想到半個月后允坚,有當?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體,經(jīng)...
    沈念sama閱讀 45,319評論 1 310
  • 正文 獨居荒郊野嶺守林人離奇死亡蛾号,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點故事閱讀 37,539評論 2 332
  • 正文 我和宋清朗相戀三年,在試婚紗的時候發(fā)現(xiàn)自己被綠了涯雅。 大學時的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片雄卷。...
    茶點故事閱讀 39,703評論 1 348
  • 序言:一個原本活蹦亂跳的男人離奇死亡衬鱼,死狀恐怖,靈堂內(nèi)的尸體忽然破棺而出,到底是詐尸還是另有隱情宪肖,我是刑警寧澤,帶...
    沈念sama閱讀 35,417評論 5 343
  • 正文 年R本政府宣布垒酬,位于F島的核電站柑潦,受9級特大地震影響,放射性物質(zhì)發(fā)生泄漏锈遥。R本人自食惡果不足惜纫事,卻給世界環(huán)境...
    茶點故事閱讀 41,013評論 3 325
  • 文/蒙蒙 一、第九天 我趴在偏房一處隱蔽的房頂上張望所灸。 院中可真熱鬧丽惶,春花似錦、人聲如沸爬立。這莊子的主人今日做“春日...
    開封第一講書人閱讀 31,664評論 0 22
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽。三九已至抡秆,卻和暖如春奕巍,著一層夾襖步出監(jiān)牢的瞬間,已是汗流浹背儒士。 一陣腳步聲響...
    開封第一講書人閱讀 32,818評論 1 269
  • 我被黑心中介騙來泰國打工的止, 沒想到剛下飛機就差點兒被人妖公主榨干…… 1. 我叫王不留,地道東北人乍桂。 一個月前我還...
    沈念sama閱讀 47,711評論 2 368
  • 正文 我出身青樓冲杀,卻偏偏與公主長得像,于是被迫代替她去往敵國和親睹酌。 傳聞我的和親對象是個殘疾皇子权谁,可洞房花燭夜當晚...
    茶點故事閱讀 44,601評論 2 353

推薦閱讀更多精彩內(nèi)容