combine
cancellable。每一个订阅都会生成一个 AnyCancellable 对象,用于控制订阅的生命周期。通过这个对象,我们可以取消订阅。当这个对象被释放时,订阅也会被取消。
/// 取消订阅
cancellable.cancel()
Combine提供了2个常用的subject: PassthroughSubject 与CurrentValueSubject
PassthroughSubject 透传事件,不会持有最新的Output
CurrentValueSubject: 除了传递事件之外,会持有最新的Output
@published : combine提供了一个Property Wrapper @Pubilshed 可以快速封装一个变量得到一个publisher
特殊的操作符 erasedToAnyPublisher,让我们可以擦除掉具体类型:
通知的声明周期绑定
1 // 存储为属性,与实例生命周期绑定
private var notificationCancellable: AnyCancellable?
private func setupNotification() {
notificationCancellable = NotificationCenter.default
.publisher(for: .yourNotification, object: nil)
.sink { [weak self] notification in
print("Received notification: (notification)")
self?.handleNotification(notification)
}
}
// 可选:手动取消订阅
func cancelNotification() {
notificationCancellable?.cancel()
notificationCancellable = nil
}
方案2:
使用 Set(最佳实践)
// 使用集合管理多个订阅
private var cancellables = Set()
NotificationCenter.default
.publisher(for: UIApplication.didBecomeActiveNotification)
.sink { [weak self] _ in
self?.appDidBecomeActive()
}
.store(in: &cancellables) // 存储到集合中
可以手动取消所有订阅:
// 手动取消所有订阅
func cancelAllSubscriptions() {
cancellables.forEach { $0.cancel() }
cancellables.removeAll()
}
Combine 发布者和订阅者涉及到的 Swift 类型
当你在 Swift 中构建管道时,函数链导致该类型被聚合为嵌套的通用类型。 如果你正在创建一个管道,然后想要将该管道作为 API 提供给代码的另一部分,则对于开发人员来说,暴露的属性或函数的类型定义可能异常复杂且毫无用处。
为了说明暴露的类型复杂性,如果你从 PassthroughSubject 创建了一个发布者,例如:
let x = PassthroughSubject<String, Never>()
.flatMap { name in
return Future<String, Error> { promise in
promise(.success(""))
}.catch { _ in
Just("No user found")
}.map { result in
return "(result) foo"
}
}
结果的类型是:
Publishers.FlatMap<Publishers.Map<Publishers.Catch<Future<String, Error>, Just>, String>, PassthroughSubject<String, Never>>
当你想要暴露这个 subject 时,所有这些混合的细节可能会让你感到非常迷惑,使你的代码更难使用。
为了清理该接口,并提供一个好用的 API,可以使用类型擦除类来包装发布者或订阅者。 这样明确隐藏了 Swift 中从链式函数中构建的类型复杂性。
用于为订阅者和发布者暴露简化类型的两个类是:
每个发布者还继承了一种便利的方法 eraseToAnyPublisher(),它返回一个 AnyPublisher 实例。 eraseToAnyPublisher() 的使用非常像操作符,通常作为链式管道中的最后一个元素,以简化返回的类型。
如果你在上述代码的管道末尾添加 .eraseToAnyPublisher():
let x = PassthroughSubject<String, Never>()
.flatMap { name in
return Future<String, Error> { promise in
promise(.success(""))
}.catch { _ in
Just("No user found")
}.map { result in
return "(result) foo"
}
}.eraseToAnyPublisher()
结果的类型将被简化为:
AnyPublisher<String, Never>
同样的技术在闭包内构造较小的管道时将非常有用。 例如,当你想在闭包中给操作符 flatMap 返回一个发布者时,你可以通过明确的声明闭包应返回 AnyPublisher 来获得更简单的类型推断。 可以在模式 有序的异步操作 中找到这样的一个例子。