本文转载自公众号“读芯术”(ID:AI_Discovery)。
想随时随地轻松变更数据格式?本文将教你5种解法!我将在Xcode Playground中创建示例函数,运行它们并观察结果。
1. map
.map 操作符允许我们转换闭包中来自发布者的所有元素。
复制
var subscriptions =Set<AnyCancellable>() funcmapExample() { let subject =PassthroughSubject<Int, Never>() subject .map { (integer) in returnString(integer) } .sink(receiveValue: { print("Value: \($0), Type: \(type(of: $0))") }) .store(in: &subscriptions) subject.send(12) subject.send(31) subject.send(55) subject.send(4) subject.send(18) }
1.
2.
3.
4.
5.
6.
7.
8.
9.
10.
11.
12.
13.
14.
15.
16.
17.
下面是这段代码的作用:
创建一个接受Int 值的PassthroughSubject。
使用.map 操作符将每个接收到的Int 值转换为String。
然后,订阅发布者并打印转换后的元素的值和类型。
向受试者发送随机数以观察以下结果:
还有一种巧妙的方法来使用对象的键路径获取对象的属性:
复制
funcmapKeyPathExample() { structCarBrand { let title:String let country:String } let carBrandsSubject =PassthroughSubject<CarBrand, Never>() carBrandsSubject .map(\.country) .sink(receiveValue: { country in print("Country:\(country)") }) .store(in: &subscriptions) carBrandsSubject.send( CarBrand(title: "MercedesBenz", country: "Germany") ) carBrandsSubject.send( CarBrand(title: "Ford", country: "USA") ) carBrandsSubject.send( CarBrand(title: "Honda", country: "Japan") ) }
1.
2.
3.
4.
5.
6.
7.
8.
9.
10.
11.
12.
13.
14.
15.
16.
17.
18.
19.
20.
21.
22.
使用.map(\.country),可以访问CarBrand的国家属性。然后只需打印每个国家:
2. replaceNil
顾名思义,.replaceNil 操作符将每个接收到的nil元素转换为指定的元素:
复制
funcreplaceNilExample() { let values: [Int?] = [123, nil, nil, 12, 10] let valuesvaluesPublisher =values.publisher valuesPublisher .replaceNil(with: 0) .map { $0! } .collect() .sink(receiveValue: { print($0) }) .store(in: &subscriptions) }
1.
2.
3.
4.
5.
6.
7.
8.
9.
10.
请注意,还可以将多个操作符组合在一起以达到必要的结果。首先将每个nil 值替换为0,然后强制解开值,最后将所有值收集在一个数组中:
需要注意的是在.map 操作符中使用强制展开的方法。如果你不喜欢强行解包该怎么办?我们还有一个.map协变量:.compactMap,它能自动转发仅非零的那些元素:
复制
funcreplaceNilExample() { let values: [Int?] = [123, nil, nil, 12, 10] let valuesvaluesPublisher = values.publisher valuesPublisher .replaceNil(with: 0) .compactMap { $0 } .collect() .sink(receiveValue: { print($0) }) .store(in: &subscriptions) }
1.
2.
3.
4.
5.
6.
7.
8.
9.
10.
3. collect
使用.collect操作符可以很容易地收集所有接收到的元素,并发出一个包含所有元素的数组:
复制
funccollectExample() { let integers = [1, 4, 5, 12, 24, 44] let integerPublisher =integers.publisher integerPublisher .collect() .sink(receiveValue: { print($0) }) .store(in: &subscriptions) }
1.
2.
3.
4.
5.
6.
7.
8.
于是我们得到了想要的结果:
注意,发布者必须发出.completed事件才能实现这个操作,因为.collect会一直等待,直到所有元素都发出并且发布者完成操作为止。例如,如果使用PassthroughSubject,需要在发送所有元素后发送.finished事件:
复制
funccollectExample() { let integerPublisher =PassthroughSubject<Int, Never>() integerPublisher .collect() .sink(receiveValue: { print($0) }) .store(in: &subscriptions) integerPublisher.send(1) integerPublisher.send(4) integerPublisher.send(5) integerPublisher.send(12) integerPublisher.send(24) integerPublisher.send(44) integerPublisher.send(completion: .finished) }
1.
2.
3.
4.
5.
6.
7.
8.
9.
10.
11.
12.
13.
14.
4. flatMap
.flatMap操作符允许我们将给定的发布者转换为另一个发布者。来看看它是如何将观察结果从Network更改为isAvailable主题:
复制
funccollectExample() { let integerPublisher =PassthroughSubject<Int, Never>() integerPublisher .collect() .sink(receiveValue: { print($0) }) .store(in: &subscriptions) integerPublisher.send(1) integerPublisher.send(4) integerPublisher.send(5) integerPublisher.send(12) integerPublisher.send(24) integerPublisher.send(44) integerPublisher.send(completion: .finished) }
1.
2.
3.
4.
5.
6.
7.
8.
9.
10.
11.
12.
13.
14.
当更改它的值时,我们要打印出isAvailable值。首先,它打印初始值(正在使用CurrentValueSubject),一旦为其分配了新值,就会发生以下情况:
5. scan
.scan操作符能够在闭包中公开当前发出的值以及最新的值。可以使用它来累积值并打印总结果:
复制
funcflatMapExample() { structNetwork { let title:String let isAvailable =CurrentValueSubject<Bool, Never>(false) } let wifi =Network(title: "Wi-Fi") let networkSubject = CurrentValueSubject<Network, Never>(wifi) networkSubject .flatMap ({ return$0.isAvailable }) .sink(receiveValue: { print("Is networkenabled: \($0)") }) .store(in: &subscriptions) wifi.isAvailable.value=true wifi.isAvailable.value=false }
1.
2.
3.
4.
5.
6.
7.
8.
9.
10.
11.
12.
13.
14.
15.
16.
17.
18.
在这里,执行的是以下操作:
创建收益数组(下划线是将数字中的千单位分开的好方法)。
创建这些收益的发布者。
使用.scan操作符,将当前发出的值($0)添加到从零开始的最新值($1)。
最后,计算出总收益:
【责任编辑:赵宁宁 TEL:(010)68476606】