zwvista

导航

Combine学习笔记

Combine

Combine是一个函数响应式编程库。

Publisher Operator Subscriber

Publisher(发布者)生成并发布数据。Publisher 是一个协议。

  • 发布者可以发布0个1个或多个数据,然后正常结束或出错。
  • 发布者的类型由所发布的数据(output,输出)的类型和所发生的错误(failure,失败)的类型构成。
    <Output Type, Failure Type>

Operator(操作符)响应和更改数据。

  • 操作符的输入类型由所接收的数据(input,输入)的类型和所接收的错误(failure,失败)的类型构成。
  • 操作符的输出类型由所生成的数据(output,输出)的类型和所发生的错误(failure,失败)的类型构成。
    <Input Type, Failure Type> to <Output Type, Failure Type>

Subscriber(订阅者)订阅数据。Subscriber 是一个协议。

  • 订阅者的类型由所接收的数据(input,输入)的类型和所接收的错误(failure,失败)的类型构成。
    <Input Type, Failure Type>
// Publisher
Just(5) 
// Operator
.map { value -> String in 
    return "a string"
}
// Subscriber
.sink { receivedValue in 
    print("The end result was \(receivedValue)")
}

Subject

Subject 是指遵循 Subject 协议的特殊发布者。Subject 协议继承自 Publisher 协议。
Subject 通过该协议中的 .send(_:) 方法来发布数据。
常用 Subject 有 CurrentValueSubject 和 PassthroughSubject。

  • PassthroughSubject 没有初值,没有当前状态(值),订阅者无法接收订阅之前发布的数据。
    PassthroughSubject 是门铃,没有开关状态,只有在家才能接收其信息。
  • CurrentValueSubject 有初值,有当前状态(值),订阅者可以接收订阅之前最后发布的数据。
    CurrentValueSubject 是电灯,有开关状态,回家即可观察其状态。

PassthroughSubject vs. CurrentValueSubject explained

let relay = PassthroughSubject<String, Never>()
let subscription = relay.sink { value in
    print("subscription1 received value: \(value)")
}
relay.send("Hello")
relay.send("World!")
/*
subscription1 received value: Hello
subscription1 received value: World!
*/
let variable = CurrentValueSubject<String, Never>("")
variable.send("Initial text")
let subscription2 = variable.sink { value in
    print("subscription2 received value: \(value)")
}
variable.send("More text")
/*
subscription2 received value: Initial text
subscription2 received value: More text
*/

Subscriber Cancellable

Is there an alternative to Combine's @Published that signals a value change after it has taken place instead of before?

常用订阅者有 sink 和 assign。
sink 使用回调函数来处理结果值。
assign 使用结果值来设置其他值。
assign(to:on:) 将结果值赋予其他某个对象的某个属性。
assign(to:) 将结果值赋予其他某个Publisher。

Cancellable (可取消)是一个协议。
sink 和 assign(to:on:) 返回 Cancellable 的实例。
通过调用 Cancellable 协议的 cancel 方法可以取消订阅。

let cancellable = publishingSource.sink { someValue in
    print(".sink() received \(someValue)")
}
// cancellable.cancel()
let cancellable = publishingSource
    .receive(on: RunLoop.main)
    .assign(to: \.isEnabled, on: yourButton)
// cancellable.cancel()
publishingSource.assign(to: &publishingSource2)

AnyPublisher AnyCancellable

AnyPublisher 为遵循 Publisher 协议的具体类。
通过调用 Publisher 协议的 eraseToAnyPublisher 方法可以将任何 Publisher 对象转化为 AnyPublisher 对象,方便统一处理并隐藏真实类型。
AnyCancellable 为遵循 Cancellable 协议的具体类。
sink 和 assign(to:on:) 返回 AnyCancellable 的实例。
AnyCancellable 的实例必须保存在该类型的变量或容器中。否则该实例会被回收并导致订阅被取消。

let pub: AnyPublisher<String, Never> = ["Here","we","go!"].publisher
    .eraseToAnyPublisher()
var subscriptions = Set<AnyCancellable>()
pub.sink { receivedValue in
    print("received value: \(receivedValue)")
}.store(in: &subscriptions)
/*
received value: Here
received value: we
received value: go!
*/

@Published

@Published 是一种提供 Publisher 的属性包装器(Property Wrapper)。
如果 v 是一个 Value 类型的属性,并且 v 属性使用 @Published 修饰,
那么 $v 就是一个 Published<Value>.Publisher 类型的 Publisher。

class Weather {
    @Published var temperature: Double
    init(temperature: Double) {
        self.temperature = temperature
    }
}
// temperature 的类型为 Double
// $temperature 的类型为 Published<Double>.Publisher
let weather = Weather(temperature: 20)
let cancellable = weather.$temperature.sink() {
    print ("Temperature now: \($0)")
}
weather.temperature = 25
// Temperature now: 20.0
// Temperature now: 25.0

posted on 2022-08-11 10:09  zwvista  阅读(72)  评论(0编辑  收藏  举报