Swift Combine — Operators(常用Filtering类操作符介绍)


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(_: )

CombinecompactMap(_:)操作符的功能与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

最后,希望能够帮助到有需要的朋友,如果觉得有帮助,还望点个赞,添加个关注,笔者也会不断地努力,写出更多更好用的文章。

  • 6
    点赞
  • 8
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值