目录
Combine
中对
Publisher
的值进行操作的方法称为
Operator
(操作符)。
Combine
中的
Operator
通常会生成一个
Publisher
,该
Publisher
处理传入事件,对其进行转换,然后将更改后的事件发送给
Subscriber
。
本篇文章主要介绍一下过滤这一类的操作符。
filter(_: )
filter
操作符主要用户过滤数据,比如下面的数据中,将大于5的数输出。
func filterSample() {
let intArray = [1, 2, 3, 4, 5, 6, 7, 8, 9]
_ = intArray.publisher
.filter {
$0 > 5
}
.sink { value in
print("value is : \(value)")
}
}
输出为:
value is : 6
value is : 7
value is : 8
value is : 9
tryFilter(_: )
使用tryFilter(_:)
来过滤在抛出错误的闭包中求值的元素。如果闭包抛出错误,则Publisher
将因该错误而失败终止。
func tryFilterSample() {
struct ZeroError: Error {}
let intArray = [1, 2, 3, 4, 5, 6, 0, 8, 9]
_ = intArray.publisher
.tryFilter {
if $0 == 0 {
throw ZeroError()
} else {
return $0 > 5
}
}
.sink(receiveCompletion: { completion in
print("Received completion: \(completion)")
}, receiveValue: { value in
print("Received value: \(value)")
})
}
当tryFilter
闭包接收到0时,抛出错误,整个Publisher
链结束。上面输出结果为:
Received value: 6
Received completion: failure((extension in CombineLearning_PreviewReplacement_OperatorDemo_1):CombineLearning.OperatorViewModel.(unknown context at $1055a3cdc).(unknown context at $1055a3ce8).ZeroError())
compactMap(_: )
Combine
的compactMap(_:)
操作符的功能与Swift标准
库中的compactMap(_:)
类似。
Combine
中的compactMap(_:)
操作符移除Publisher流中的nil元素,并将非nil元素重新发布给下游订阅者。
func compactMapSample() {
let numbers = (0...5)
let romanNumeralDict: [Int : String] = [1: "one", 2: "two", 3: "three", 5: "five"]
_ = numbers.publisher
.compactMap { romanNumeralDict[$0] }
.sink { print("\($0)", terminator: " ") }
}
当通过key为4的值的时候为nil了,所以这里将nil去除了。
输出结果为:
one two three five
tryCompactMap(_: )
tryCompactMap(_: )
相比compactMap(_:)
除了都能去除nil外,前者还能在闭包内抛出错误。
如果闭包抛出错误,则Publisher
流将因该错误而失败终止。
func tryCompactMapSample() {
struct ParseError: Error {}
func romanNumeral(from: Int) throws -> String? {
let romanNumeralDict: [Int : String] =
[1: "one", 2: "two", 3: "three", 4: "four", 5: "five"]
guard from != 0 else { throw ParseError() }
return romanNumeralDict[from]
}
let numbers = [6, 5, 4, 3, 2, 1, 0]
_ = numbers.publisher
.tryCompactMap { try romanNumeral(from: $0) }
.sink(
receiveCompletion: { print ("\($0)") },
receiveValue: { print ("\($0)", terminator: " ") }
)
}
在上面代码中,当取key为6的元素时为nil,这个nil没有继续往下发送。当取key为0的元素时,抛出了错误,随后Publisher
流结束。
输出结果为:
five four three two one failure((extension in CombineLearning_PreviewReplacement_OperatorDemo_1):CombineLearning.OperatorViewModel.(unknown context at $104a0bbec).(unknown context at $104a0bbf8).ParseError())
removeDuplicates()
有些时候下游的订阅者不希望收到重复的数据,那么用removeDuplicates
方法可以去除重复数据。
func removeDuplicatesSample() {
let intArray = [1, 1, 3, 5, 5, 6, 7, 8, 9]
_ = intArray.publisher
.removeDuplicates()
.sink { value in
print("value is : \(value)")
}
}
上面代码中将数组中重复的数据去除,然后输出。
输出为:
value is : 1
value is : 3
value is : 5
value is : 6
value is : 7
value is : 8
value is : 9
另外需要注意removeDuplicates
操作符不会将Publisher
作为一个集合去排重,而是随着时间根据上下接收到的数据排重,如果相同的数据不挨着,那么不会认为是重复的。
func removeDuplicatesSample() {
let intArray = [1, 1, 3, 5, 5, 6, 7, 1, 5]
_ = intArray.publisher
.removeDuplicates()
.sink { value in
print("value is : \(value)")
}
}
上面数组中在末尾又添加了1和5,看看输出结果:
value is : 1
value is : 3
value is : 5
value is : 6
value is : 7
value is : 1
value is : 5
first(where:)
first(where:)
操作符和filter
操作符很相似,filter
是找出所有满足条件的数据,而first(where:)
操作符是找出第一个满足条件的数据。
func firstWhereSample() {
let intArray = [1, 2, 3, 3, 5, 6, 7, 8, 9]
_ = intArray.publisher
.first {
$0 > 5
}
.sink(receiveCompletion: { completion in
print("Received completion")
}, receiveValue: { value in
print("Received value: \(value)")
})
}
比如上面代码找出第一个大于5的数据,结果如下:
Received value: 6
Received completion
last(where:)
last(where:)
和first(where:)
操作符正好相反, last(where:)
操作符查找符合条件的最后一个数据。
func lastWhereSample() {
let intArray = [1, 5, 3, 7, 2, 6, 4, 8, 9]
_ = intArray.publisher
.last {
$0 < 6
}
.sink(receiveCompletion: { completion in
print("Received completion")
}, receiveValue: { value in
print("Received value: \(value)")
})
}
上面代码找出小于6的最后一个元素,输出结果为:
Received value: 4
Received completion
如果是找出大于6的最后一个元素,输出结果为:
Received value: 9
Received completion
最后,希望能够帮助到有需要的朋友,如果觉得有帮助,还望点个赞,添加个关注,笔者也会不断地努力,写出更多更好用的文章。