• [SwiftUI 开发] Combine使用方法


     这片主要介绍Combine基本用法

     1. Just

    1. let myPublisher = Just("1")
    2. let myScriber = Subscribers.Sink<String, Never> { completion in
    3. if completion == .finished {
    4. print("myScriber1 Finished")
    5. } else {
    6. print("myScriber1 Failure")
    7. }
    8. } receiveValue: { value in
    9. print(value)
    10. }
    11. myPublisher.subscribe(myScriber)
    12. 打印结果:
    13. // 1
    14. // myScriber1 Finished

    1. Just发布一个Publisher,just只会发送一次,发送完成结束本次订阅
    2. Sink订阅者,订阅了Just,这个Sink后面是个泛型

            第一参数是参数类型,方法Just发送的是String类型,所以咱们观察者类型要保持一致

            第二参数是错误类型,例子中参数是Never,就是不会报错,下面的例子中会介绍其它的
    3.  Sink中有两个闭包 (receiveCompletion和receiveValue)

            receiveCompletion: 结束观察订阅
            receiveValue: 订阅结果

    1. extension Publisher {
    2. public func sink(receiveCompletion: @escaping ((Subscribers.Completion<Self.Failure>) -> Void), receiveValue: @escaping ((Self.Output) -> Void)) -> AnyCancellable
    3. }
    4. extension Publisher where Self.Failure == Never {
    5. public func sink(receiveValue: @escaping ((Self.Output) -> Void)) -> AnyCancellable
    6. }
    7. // 如果不需要receiveCompletion,我们可以用Self.Failure == Never方法

    2. Publishers

    Publishers处于pipline的最上游,它的主要作用是发送数据

    1. let arr = 0...3
    2. arr.publisher.sink { value in
    3. print(value)
    4. }
    5. 打印结果:
    6. // 0
    7. // 1
    8. // 2
    9. // 3

    Combine给了我们一个简便的写法

    适用环境,比如我们在意的是直接拿到结果,不需要中间的Operator
     

    3. assign

    1. class Person {
    2. var age: Int = 0 {
    3. didSet {
    4. print("age: \(age)")
    5. }
    6. }
    7. }
    8. let person = Person()
    9. let range = 0...2
    10. range.publisher.assign(to: \.age, on: person)
    11. 打印结果:
    12. // 0
    13. // 1
    14. // 2

    keyPath

    将发布者中的每个元素分配给对象上的属性。

    使用Publisher/assign(to:on:)订阅者,当你想在每次发行者产生一个值时设置给定的属性。

    在这个例子中,Publisher/assign(to:on:) 在person的实例上设置age属性的值

    第二种用法

    1. class Person {
    2. @Published var age: Int = 0
    3. }
    4. let person = Person()
    5. Just(1).assign(to: &person.$age)
    6. print(person.age)
    7. 打印结果:
    8. // 1

    熟悉SwiftUI的朋友看起来比较喜欢,属性包装器的写法

    ** assign 都是 Self.Failure == Never

    4. Future

    1. class Person {
    2. var age: Int = 0
    3. }
    4. let futurePubliser = Future<Int ,Never> { promise in
    5. print("异步操作")
    6. promise(.success(2))
    7. }
    8. let subscribers = Subscribers.Sink<Int,Never> { completion in
    9. if completion == .finished {
    10. print("Finished")
    11. } else {
    12. print("Failure")
    13. }
    14. } receiveValue: { value in
    15. print(value)
    16. }
    17. futurePubliser.subscribe(subscribers)
    18. let person = Person()
    19. futurePubliser.assign(to: \.age, on: person)
    20. 打印结果:
    21. // 异步操作
    22. // 2
    23. // Finished

    Future和Just类似,区别在于:

            Just直接发送参数, Failure = Never
            Futrre是调用一个异步闭包,可以选择闭包结束时发送数据, Failure = Error

    5. Operator

    1. let myPubliser2 = Just("1")
    2. let tansValue = Publishers.Map<Just<String>, Int>(upstream: myPubliser2) { value in
    3. return Int(value) ?? 0
    4. }
    5. let myScriber2 = Subscribers.Sink<Int,Never> { completion in
    6. if completion == .finished {
    7. print("Finished")
    8. } else {
    9. print("Failure")
    10. }
    11. } receiveValue: { value in
    12. print(value)
    13. }
    14. tansValue.subscribe(myScriber2)
    15. 打印结果:
    16. // 1
    17. // Finished

    使用提供的闭包转换来自上游发布者的所有元素的发布者

    Operator处于pipline的中游,它的主要作用是接收数据,处理数据,再发送数据

    此发布者可能发布的错误类型, 此发布者使用其上游发布者的失败类型。

    6. Operator2

    1. _ = Just(1).filter({ value in
    2. return value < 10
    3. }).sink(receiveCompletion: { completion in
    4. if completion == .finished {
    5. print("Finished")
    6. } else {
    7. print("Failure")
    8. }
    9. }, receiveValue: { value in
    10. print(value)
    11. })
    12. 打印结果:
    13. // 1
    14. // Finished
    1. extension Just {
    2. public func filter(_ isIncluded: (Output) -> Bool) -> Optional<Output>.Publisher
    3. }

    注意这个filter,它不是高阶函数里的那个filter,虽然它们功能都是数据过滤。但它属于Just, 它返回的是Publisher

    7. CurrentValueSubject  send

    1. // 定义一个错误类型
    2. enum myErrors: Error {
    3. case wrongValue
    4. }
    5. // 定义一个publiser
    6. let publiser = CurrentValueSubject<String, myErrors>("10")
    7. // 第一个接收者
    8. publiser.filter {
    9. return $0.count < 2
    10. }.sink { completion in
    11. if completion == .failure(myErrors.wrongValue) {
    12. print("Scriber1 Finished")
    13. } else {
    14. print("Scriber1: \(completion)")
    15. }
    16. } receiveValue: { value in
    17. print("Scriber1: \(value)")
    18. }
    19. // 第二个接收者
    20. let myScriber = Subscribers.Sink<String,myErrors> { completion in
    21. if completion == .failure(myErrors.wrongValue) {
    22. print("Scriber2 Finished")
    23. } else {
    24. print("Scriber2: \(completion)")
    25. }
    26. } receiveValue: { value in
    27. print("Scriber2: \(value)")
    28. }
    29. publiser.subscribe(myScriber)
    30. // 开始发送数据
    31. publiser.send("1")
    32. publiser.send("11")
    33. publiser.send(completion: .failure(.wrongValue))
    34. publiser.send("over")
    35. 打印结果:
    36. // Scriber2: 10
    37. // Scriber1: 1
    38. // Scriber2: 1
    39. // Scriber2: 11
    40. // Scriber1 Finished
    41. // Scriber2 Finished

    CurrentValueSubject可以订阅一个publiser, 它可以多点用send发布数据,直到发送completion结束观察

    Failure = Error

    8. CurrentValueSubject  Operator

    1. let subject1: CurrentValueSubject<Int,myErrors> = .init(10)
    2. let subject2: CurrentValueSubject<Int,myErrors> = .init(20)
    3. // 数据流 subject1 -> subject2
    4. _ = subject1.subscribe(subject2)
    5. let myScriber = Subscribers.Sink<Int,myErrors> { completion in
    6. if completion == .finished {
    7. print("Finished")
    8. } else {
    9. print("Failure")
    10. }
    11. } receiveValue: { value in
    12. print(value)
    13. }
    14. subject2.receive(subscriber: myScriber)
    15. subject1.send(1)
    16. subject1.send(2)
    17. subject2.send(3)
    18. subject1.send(completion: .failure(.wrongValue))
    19. subject1.send(11)
    20. subject2.send(12)
    21. 打印结果:
    22. // 10
    23. // 1
    24. // 2
    25. // 3
    26. // Failure

    CurrentValueSubject也可以当作Operator适用
    例子中subject1处于pipline的上游,subject2处于pipline的中游

    Failure = Error

    subject1.send(1)      //  subject1 -> subject2 ->Scriber
    subject1.send(2)      //  subject1 -> subject2 ->Scriber
    subject2.send(3)      //  subject2 ->Scriber
    subject1.send(completion: .failure(.wrongValue))   //  结束myScriber的响应者

    9. PassthroughSubject

    1. let subject1: PassthroughSubject<Int,myErrors> = PassthroughSubject()
    2. let subject2: PassthroughSubject<Int,myErrors> = PassthroughSubject()
    3. // 数据流 subject1 -> subject2
    4. let cancelable = subject1.subscribe(subject2)
    5. let myScriber = Subscribers.Sink<Int,myErrors> { completion in
    6. if completion == .finished {
    7. print("Finished")
    8. } else {
    9. print("Failure")
    10. }
    11. } receiveValue: { value in
    12. print(value)
    13. }
    14. subject2.receive(subscriber: myScriber)
    15. subject1.send(1)
    16. subject1.send(2)
    17. subject2.send(3)
    18. subject1.send(completion: .failure(.wrongValue))
    19. subject1.send(11)
    20. subject2.send(12)
    21. 打印结果:
    22. // 1
    23. // 2
    24. // 3
    25. // Failure

    PassthroughSubject和CurrentValueSubject功能类似

    区别在于

            CurrentValueSubject: 有个初始化值

            PassthroughSubject:没有初始化值

  • 相关阅读:
    vue3.x中父组件添加自定义参数后,如何获取子组件$emit传递过来的参数
    (万字详解)指针进阶
    贝叶斯推理三种方法:MCMC 、HMC和SBI
    P 进阶_(eval 函数)
    Vue2与Vue3区别-computed、watch、watchEffect
    大厂纷纷调整员工福利:快手取消免费三餐,新浪为员工父母配30万重疾险
    二百三十四、Linux——导出CentOS 7已安装的软件包为离线安装包
    【MYSQL】表的综合查询
    金融领域思考-前言
    git push入门
  • 原文地址:https://blog.csdn.net/u010130947/article/details/126847697