Publisher(发布者)是一种“可被订阅的消息源”,负责发布单个值或多个值。
Publisher协议
Swift定义的Publisher协议:
protocol Publisher {
associatedtype Output
associatedtype Failure: Error
func receive<S>(subscriber: S) where S: Subscriber, Failure == S.Failure, Output == S.Input
}
协议表示Publisher可以把某种类型的值(Output)或某种类型的错误(Failure)发送给订阅者(Subscriber)。
1、associatedtype Output
associatedtype Output
Output表示发布的值,例如:
Just(3) // Output = Int
Just(Date()) // Output = Date
[1,2,3].publisher // Output = Int
2、associatedtype Failure: Error
associatedtype Failure: Error
Failure表示失败类型,例如:
Just(3).Failure == Never
Just永远不会失败,所以它的失败类型为 Never。
URLSession.shared.dataTaskPublisher(...)
dataTaskPublisher可能会失败,所以失败类型为URLError。
3、recive(subscriber:)
func receive<S>(subscriber: S) where S: Subscriber, Failure == S.Failure, Output == S.Input
recive表示如果需要订阅发布者,必须是一个Subscriber(订阅者)。
Output == S.Input
表示Publisher(发布者)的值和Subscriber(订阅者)接收的类型需要一致。
例如,Publisher发Date类型的值,Subscriber必须接收Date类型。
Failure == S.Failure
表示如果Publisher发送错误类型,Subscriber也必须接收,这保证错误不会出现“类型不匹配”的问题。
当订阅发生时:
publisher.sink { value in
print(value)
}
sink创建了一个Subscriber(订阅者)。
sink调用:
publisher.receive(subscriber: sinkSubscriber)
Publisher开始工作。
常用Publisher类型
1、Just:发送一个值后结束,用于测试、默认值。
Just(Date())
当订阅Just类型的Publisher时,Just会立即发布该值。
例如:
let num = Just(2)
let doubleNum = num
.map { $0 * 2}
.sink { value in
print("\(value)") // 4
}
2、PassthroughSubject:随时发送值,用于动态事件。
PassthroughSubject<String, Never>()
没有初始值,需要手动调用 .send(_:) 发布数据,只能发布订阅后产生的值。
例如,
let message = PassthroughSubject<String, Never>()
let subscription = message.sink{ sub in
print(sub)
}
message.send("GitHub宕机啦!")
message.send("Cloudflare也宕机啦!")
message.send("AWS也宕机啦!")
当调用send方法时,会发布对应的值,常用于处理用户交互、通知或其他需要即时传播的事件。
如果不传值,只触发事件,可以使用:
PassthroughSubject<Void, Never>()
配合 send() 方法使用:
pastePublisher.send() // 不需要任何参数
当调用send()方法时,订阅者可以接收值或事件。
3、CurrentValueSubject:保留一个最新值,同时可以发送新值。
CurrentValueSubject<Int, Never>(10)
持有一个初始值,订阅者会收到当前值,需要手动调用 .send(_:) 更新值。
let message = CurrentValueSubject<Int, Never>(10)
Text("\(message.value)") // 10
Button("更新Publisher") {
message.send(20) // 发布后,message 变成 20
}
4、Fail:立即失败,用于模拟错误流。
5、Empty:不发送任何值,用于占位流、条件跳过。
6、Deferred:延迟创建 Publisher,按需惰性生成。
7、Future:执行一次异步任务后发出值,用于网络请求、延迟操作。
8、Record:发送固定事件序列,用于测试使用。
9、Publishers.Sequence:来自 .publisher 的数组等,用于批量静态值。
[1, 2, 3].publisher
订阅者订阅时,或者依次获取每个静态值:
[1, 2, 3].publisher
.sink { value in
print(value) // 依次输出 1、2、3
}
这个Publisher的Output是Int,不是[Int],这是因为Publisher的真实类型是:
Publishers.Sequence<[Int], Never>
Publishers.Sequence的定义为:
struct Publishers.Sequence<SequenceType, Failure>
where SequenceType: Swift.Sequence {
typealias Output = SequenceType.Element // 拆分数组
}
对于[Int]来说:
SequenceType == [Int]
SequenceType.Element == Int
所以Output为Int。
10、Publishers.Once:.publisher from Optional,一次性 optional。
11、Publishers.Share:多个订阅共享同一输出,网络共享。
12、Publishers.Timer:来自 Timer.publish(),用于定时事件流。
13、Publishers.Merge, Zip, CombineLatest:组合多个 Publisher,响应多个数据源。
14、Publishers.HandleEvents, TryMap, 等操作符变种:添加副作用、错误捕获等,用于调试、流程控制。
总结
除了内置的Publisher外,Swift标准库还有多个类型被扩展为Combine的Publisher:
1、Array、Set、Dictionary等类型,.publisher可以将集合转换为Publisher。
var num = [1,2,3]
num.publisher
.sink{ value in
print("\(value)") // 分别输出1,2,3
}
2、Optional可选值,.publisher支持将可选值转换为Publisher。
3、NotificationCenter通知,.publisher(for:)方法转换为Publisher。
4、URLSession会话,.dataTaskPublisher(for:)方法转换为Publisher。
5、KVO对象,.publisher(for:)方法转换为Publisher。
6、Timer计时器,.publish方法转换为Publisher。
更多扩展为Publisher的类型请见《Swift常见的支持Publisher响应式处理的类或常见》。
