在这个ViewModel代码中,allCreations、allCreationsRelay 和 allCreationsPublisher 是三个关联但作用不同的变量。
// 变量 allCreations
private var allCreations: [CreationModel] = []
// 变量的PassthroughRelay
private let allCreationsRelay = PassthroughRelay<[CreationModel]>()
// 变量对应的AnyPublisher
var allCreationsPublisher: AnyPublisher<[CreationModel], Never> {
allCreationsRelay.eraseToAnyPublisher()
}
------------------------------
// 订阅
allCreationsPublisher
.map({ $0.filter({ $0.isDot }).count })
.removeDuplicates()
.sink(receiveValue: { [weak self] count in
self?.dotNumber = count
}).store(in: &cancellables)
allCreations:
这是一个普通的数组,类型为 [CreationModel],它存储了所有的作品数据;allCreationsRelay:
allCreationsRelay 是一个 PassthroughRelay<[CreationModel]>,它是一个 Combine 的专用对象,用来“传递”数据;allCreationsPublisher:
allCreationsPublisher 是 allCreationsRelay.eraseToAnyPublisher() 的结果,它将 allCreationsRelay 转换为一个可以公开订阅的 Publisher。
为什么不能直接订阅allCreationsRelay?
针对 allCreationsRelay
和 allCreationsPublisher
的存在意义:两个变量之间的关系实际上是通过 PassthroughRelay
和 AnyPublisher
来实现的。
PassthroughRelay
的作用:
allCreationsRelay
是一个PassthroughRelay<[CreationModel]>
,这实际上是一个对象,它用于在内部管理数据流。PassthroughRelay
是一个特殊的类型,它结合了PassthroughSubject
和Relay
的特性,允许我们发布一个事件流,但它本身并不遵循公开发布的规范,不能直接作为公共 API 使用。封装和数据流控制:
allCreationsRelay
只是一个底层的容器,充当了对外界通知的角色。为了提供更强的封装性、解耦和可测试性,我们通常会暴露一个AnyPublisher
类型的数据流,而不是直接暴露一个PassthroughRelay
对象。通过暴露allCreationsPublisher
(AnyPublisher<[CreationModel], Never>
),外部只能订阅这个封装后的流,而不需要关心它如何被更新。这样做符合封装和数据流的控制原则。AnyPublisher
的意义:
allCreationsPublisher
是一个通过.eraseToAnyPublisher()
封装的AnyPublisher
,它是PassthroughRelay
公开的接口。AnyPublisher
封装了PassthroughRelay
,让外部只能订阅、观察这个流,而不能修改它。这种方式可以保证外部只能读取数据,而不会意外修改它,增加了代码的健壮性。
allCreationsRelay
是一个内部的可变数据流,供内部使用来发布数据变更;
allCreationsPublisher
是一个对外公开的、封装后的不变数据流,它用于外部订阅者接收数据变化。
通过这样的封装,ViewModel
内部可以自由地更新 Relay
数据,而外部的订阅者只能监听变化,无法直接修改数据流,这有助于提高代码的清晰度和可维护性。