Combine(二) Operators

Combine有很多方便的方法: Operators。这些operators可以把从publisher传出来的values一层一层的过滤/筛选/变型,subscriber就可以拿到自己真正需要的values了。

1、collect()

collect就是把一个一个输出的value全都放在array里,然后等publisher结束后,输出这个array:

["A", "B", "C", "D", "E"].publisher
  .collect()
  .sink(receiveCompletion: { print($0) },
        receiveValue: { print($0) })
    .store(in: &subscriptions)

// ["A", "B", "C", "D", "E"]
// finished

通常我们会限制collect需要收集values的个数,不然无限等着可能浪费内存:

.collect(2)

// ["A", "B"]
// ["C", "D"]
// ["E"]
// finished

2、map()

这和swift中的用法一样

["A", "B", "C"].publisher
    .map { $0 + $0 }
    .sink(receiveCompletion: { print($0) },
        receiveValue: { print($0) })
    .store(in: &subscriptions)

AA
BB
CC
finished

3、map key path

如果输出的value有多个属性,那么也可以用map和keypath来拆分:

[(x: 2, y: 3), (x: 1, y: 5), (x: 2, y: 6)].publisher
    .map(\.x, \.y)
    .sink(receiveCompletion: { print($0) },
        receiveValue: { x, y in print(x + y) })
    .store(in: &subscriptions)

5
6
8
finished

4、tryMap

tryMap就是map的closure里有可能throw,throw的话就筛选掉这个value:

Just("/fake")
    .tryMap { try FileManager.default.contentsOfDirectory(atPath: $0) }
    .sink(receiveCompletion: { print($0) },
        receiveValue: { print($0) })
    .store(in: &subscriptions)

No such file or directory

5、flatMap

如果你有一个publisher发送的value的某些属性也是publisher, 那sink只会receive外面这个publisher发出的value,属性publisher发出的value要是也想接收,那你就可以用flatMap

struct Person {
    let name : String
    var age: CurrentValueSubject
    
    init(name: String, age: Int) {
        self.name = name
        self.age = CurrentValueSubject(age)
    }
}

var me = Person(name: "Joshua", age: 18)
var you = Person(name: "Dog", age: 28)

let people = PassthroughSubject()
people
    .flatMap{ $0.age }
    .sink(receiveCompletion: { _ in
        print("people completed")
    }, receiveValue: { val in
        print(val)
    })

people.send(me)
people.send(you)
me.age.value = 19
you.age.value = 30

//输出
18
28
19
30

好好看一下这个例子,我觉得大家应该就都理解了吧,这属于比较复杂的一个operator了。flatMap还可以限制订阅publisher的个数:

var me = Person(name: "Joshua", age: 18)
var you = Person(name: "Dog", age: 28)
var she = Person(name: "SHE", age: 16)

let people = PassthroughSubject()
people
    .flatMap(maxPublishers: .max(2)) { $0.age }
    .sink(receiveCompletion: { _ in
        print("people completed")
    }, receiveValue: { val in
        print(val)
    })

people.send(me)
people.send(you)
people.send(she)
me.age.value = 19
you.age.value = 30
she.age.value = 17

// 输出和之前那个一样

6、replaceNil(with:)

"人"如其名的这种我就不解释了

["A", nil, "C"].publisher
.replaceNil(with: "null")
.map { $0! }
.sink(receiveCompletion: { print($0) },
    receiveValue: { print($0) })
.store(in: &subscriptions)

A
null
C
finished

7、replaceEmpty(with:)

let empty = Empty()
empty
.replaceEmpty(with: "Empty")
.sink(receiveCompletion: { print($0) },
    receiveValue: { print($0) })
.store(in: &subscriptions)

Empty
finished

这个Empty一般就是用来测试或demo,直接发送.finish

8、reduce(0)

这个和之前文章中介绍的reduce一样。publisher一定要结束才会输出最后值

[1, 2, 3].publisher
    .reduce(0, +)
    .sink(receiveCompletion: { print($0) },
        receiveValue: { print($0) })
    .store(in: &subscriptions)

6
finished

9、scan

scan和reduce差不多,但是scan不是最后才输出值,每个都会输出

[1, 2, 3].publisher
    .scan(0, +)
    .sink(receiveCompletion: { print($0) },
        receiveValue: { print($0) })
    .store(in: &subscriptions)

1
3
6
finished

10、filter

[1, 2, 3].publisher
    .filter { $0 < 2 }
    .sink(receiveCompletion: { print($0) },
        receiveValue: { print($0) })
    .store(in: &subscriptions)

1
finished

11、removeDuplicates()

注意这个并不是所有重复的都去掉,只是publisher当前要发出的value和上个发出的一样的才会去掉。要让系统排重,那value一定是Equatable, 不然你就得自定义相等的条件:

[1, 1, 2].publisher
    .removeDuplicates()
    .sink(receiveCompletion: { print($0) },
        receiveValue: { print($0) })
    .store(in: &subscriptions)

1
2
finished

12、compactMap

跟swift中的一样,会删掉invalid的值

["1", "a", "2"].publisher
    .compactMap { $0 }
    .sink(receiveCompletion: { print($0) },
        receiveValue: { print($0) })
    .store(in: &subscriptions)

1
2
finished

13、ignoreOutput()
只想知道publisher是不是结束了,不care他发出了什么value

14、first() 和 first(where:)

接收到第一个值就取消订阅,可以用where加条件

[1, 2, 3].publisher
    .first { $0 > 1 }
    .sink(receiveCompletion: { print($0) },
        receiveValue: { print($0) })
    .store(in: &subscriptions)

2
finished

15、last()和last(where:)

跟上一个一样,唯一区别是publisher必须结束才会输出,原因不用说了吧

16、dropFirst()

.dropFirst(3)就是不要前3个

17、drop(while:)

直到while的条件符合,都不要!但一旦符合条件了,后面的都要!

[1, 2, 3, 4, 5].publisher
    .drop(while: { $0 < 3 })
    .sink(receiveCompletion: { print($0) },
        receiveValue: { print($0) })
    .store(in: &subscriptions)

3
4
5
finished

18、drop(untilOutputFrom:)

这个其实也很简单理解,就是你有两个publisher,用这个operator的publisher必须要等另一个publisher输出才会输出,之前的都不要了

19、prefix()、prefix(while:)、prefix(untilOutputFrom:)

跟drop的三个正好相反,保留前几个values直到....唯一要注意的是,跟first一样,符合条件之后就cancel

20、prepend()

在publisher输出之前先输出prepend里面的同类型values

[1, 2, 3].publisher
    .prepend(9, 8) // 也可以prepend([9, 8]),结果一样
    .sink(receiveCompletion: { print($0) },
        receiveValue: { print($0) })
    .store(in: &subscriptions)

9
8
1
2
3
finished

还可以prepend(另一个publisher),这样只有prepend的publisher完成输出,本来的publisher才开始输出

21、append()

嗯没错,跟之前相反,但你要注意,只有publisher结束了,才会输出append的values

现写到这儿...还有一半...shit...

你可能感兴趣的:(Combine(二) Operators)