Combine发布者Publisher
Combine发布者Publisher

Combine发布者Publisher

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响应式处理的类或常见》。

   

如果您认为这篇文章给您带来了帮助,您可以在此通过支付宝或者微信打赏网站开发者。

欢迎加入我们的 微信交流群QQ交流群,交流更多精彩内容!
微信交流群二维码 QQ交流群二维码

发表回复

您的电子邮箱地址不会被公开。 必填项已用 * 标注