欢迎来到尧图网

客户服务 关于我们

您的位置:首页 > 教育 > 锐评 > Swift Combine — Subject Publishers(PassthroughSubject CurrentValueSubject)

Swift Combine — Subject Publishers(PassthroughSubject CurrentValueSubject)

2024/11/30 18:49:01 来源:https://blog.csdn.net/guoyongming925/article/details/139727027  浏览:    关键词:Swift Combine — Subject Publishers(PassthroughSubject CurrentValueSubject)

本文主要介绍一下SubjectSubject 本身也是一个 Publisher,其定义如下:

public protocol Subject<Output, Failure> : AnyObject, Publisher {func send(_ value: Self.Output)func send(completion: Subscribers.Completion<Self.Failure>)func send(subscription: any Subscription)
}

从定义可以看到,Subject 暴露了三个 send 方法,外部调用者可以通过这些方法来主动地发布 output 值、failure 事件、 finished 事件以及subscription

Combine 内置提供了两种常用的 Subject 类型,分别是 PassthroughSubjectCurrentValueSubject,下面来分别看一下。

PassthroughSubject

PassthroughSubjectCombine框架中的一种Subject具体类型,它不持有任何值,将自己接收到的任何值简单的传递给下游的Subscriber

当我们要创建一个PassthroughSubject时,需要指定要发送的值的类型,然后使用send方法发送,任何的Subscriber都会收到这个值。因为它本身不持有值,所以如果下游没有Subscriber,那么这个值将废弃了。

  func testPassthroughSubjectPublisher() {let publish2 = PassthroughSubject<String, Error>()publish2.send("1")publish2.sink { completion inswitch completion {case .finished:print("---> Finished")case .failure(let error):print("---> Error: \(error.localizedDescription)")}} receiveValue: { value inprint("---> value is: \(value)")}.store(in: &cancellable)publish2.send("2")publish2.send(completion: .finished)}

上面代码中创建了PassthroughSubject实例publish2,并通过sink方法添加了订阅者,订阅后,随后通过send方法发送了2.finished事件,sink方法中对应的输出都正常。但是在添加sink方法之前发送的send("1")没有任何输出,就像上面说的,发送的时候还没有任何订阅者,发送的值就直接抛弃了。

输出结果:

---> value is: 2
---> Finished

作为Subject的具体实现,PassthroughSubject提供了一种方便的方法,使现有的命令式代码适应Combine模型。

CurrentValueSubject

CurrentvaluessubjectCombine框架中的一种Subject具体类型。它可以保存单个值,并在设置新值时向任何订阅者发布新值。
Currentvaluessubject在初始化的时候需要设置一个初始值。

let publisher = CurrentValueSubject<String, Error>("one")

当有订阅者订阅的时候会立即发送这个值。下面代码中当初始化CurrentValueSubjectViewModel的时候,则会直接输出“—> value is: one”

class CurrentValueSubjectViewModel: ObservableObject {init() {setUpPublisher()}func setUpPublisher() {let publisher = CurrentValueSubject<String, Error>("one")let cancelable = publisher.sink { completion inswitch completion {case .finished:print("---> Finished")case .failure(let error):print("---> Error: \(error.localizedDescription)")}} receiveValue: { value inprint("---> value is: \(value)")}}
}

下面代码中,在viewModel中实例化了一个CurrentValueSubject,并添加了subscriber,在SwiftUI界面添加了三个按钮,用来发送数据。

在发送数据的时候,可以通过send方法,也可以通过直接设置value的方法,效果都是一样的。

class CurrentValueSubjectViewModel: ObservableObject {private var cancellable = Set<AnyCancellable>()let publisher = CurrentValueSubject<String, Error>("one")init() {setUpPublisher()}func setUpPublisher() {publisher.sink { completion inswitch completion {case .finished:print("---> Finished")case .failure(let error):print("---> Error: \(error.localizedDescription)")}} receiveValue: { value inprint("---> value is: \(value)")}.store(in: &cancellable)}func sendMessage() {publisher.send("Hello World")publisher.value = "Swift Combine"}func sendError() {publisher.send(completion: .failure(NetworkError.invalidURL))}func sendFinished() {publisher.send(completion: .finished)}}struct CurrentValueSubjectDemo: View {@StateObject private var viewModel = CurrentValueSubjectViewModel()var body: some View {VStack {Button("Send Message") {viewModel.sendMessage()}Button("Send Finished") {viewModel.sendFinished()}Button("Send Error") {viewModel.sendError()}}.buttonStyle(BorderedProminentButtonStyle())}
}

当点击按钮时,输出如下:
在这里插入图片描述

关于Subject生命周期

Subject是有生命周期的,放发送了completion后(不管是finished还是error),Subject都不会再发送任何新值。

就上面的CurrentValueSubject为例,在发送一个value之后,就发送finished,然后在发送value就无效了。
在这里插入图片描述
PassthroughSubject亦是如此。所以当使用PassthroughSubjectCurrentValueSubject时,重要的是要考虑生命周期,并在明显没有任何值发送时关闭Subject

PassthroughSubject与CurrentValueSubject区别

首先这两个都是Subject的具体实现,都可以根据需要异步地无限地发出事件。这两个Subject的用法都比较简单,都作为Publisher发布数据,不过却别还是有的。

PassthroughSubject没有初始值,也不需要持有最近一次发布的值。
CurrentValueSubject可以为Publisher提供初始值,并通过更新 value属性自动发出事件。

网上有一个较为恰当的比喻:
PassthroughSubject就像一个门铃按钮。当有人按门铃时,只有当你在家时才会通知你。
CurrentValueSubject就像一个电灯开关。当你不在的时候灯是开着的,当你回家的时候你仍然会注意到它是开着的。

写在最后

本文主要介绍了PassthroughSubjectCurrentValueSubject的概念、使用以及一些区别,希望大家通过本文能对这两个Subject有个初步的了解和使用,文中如果有不对的地方,还望大家指正。

最后,希望能够帮助到有需要的朋友,如果觉得有帮助,还望点个赞,添加个关注,笔者也会不断地努力,写出更多更好用的文章。

版权声明:

本网仅为发布的内容提供存储空间,不对发表、转载的内容提供任何形式的保证。凡本网注明“来源:XXX网络”的作品,均转载自其它媒体,著作权归作者所有,商业转载请联系作者获得授权,非商业转载请注明出处。

我们尊重并感谢每一位作者,均已注明文章来源和作者。如因作品内容、版权或其它问题,请及时与我们联系,联系邮箱:809451989@qq.com,投稿邮箱:809451989@qq.com