just
代码示例, Just
:
使用 Subscribers.Sink
先声明再组装的方式:
swift
let mySubjuect = Just(4)
let subscriber = Subscribers.Sink<Int, Never /*never表示没有数据类型*/ > { finish in
if finish == .finished {
print("success")
} else { // 不会执行,just无错误
print("error")
}
} receiveValue: { value in
print(value)
}
let subscriber1 = Subscribers.Sink<Int, Never /*never表示没有数据类型*/ > { finish in
} receiveValue: { value in
print(value)
}
mySubjuect.receive(subscriber: subscriber)
mySubjuect.receive(subscriber: subscriber1)
let mySubjuect = Just(4)
let subscriber = Subscribers.Sink<Int, Never /*never表示没有数据类型*/ > { finish in
if finish == .finished {
print("success")
} else { // 不会执行,just无错误
print("error")
}
} receiveValue: { value in
print(value)
}
let subscriber1 = Subscribers.Sink<Int, Never /*never表示没有数据类型*/ > { finish in
} receiveValue: { value in
print(value)
}
mySubjuect.receive(subscriber: subscriber)
mySubjuect.receive(subscriber: subscriber1)
使用 .publisher 与 .sink
也可以将数组、区间等通过.publisher
语法作为一个发布者。
sink相关方法有:
.sink(receiveValue: closure)
- 仅关注结果输出
sink(receiveCompletion:closure, receiveValue:closure)
:- 可以获取结束状态
swift
let range: ClosedRange<Int> = 0 ... 3
// 专注于结果输出
_ = range.publisher
.sink { value in
print(value) // 0 1 2 3
}
// 可以获取结束状态
_ = range.publisher.sink { completion in
if completion == .finished {
print("completion")
}
} receiveValue: { element in
print("element", element)
}
let range: ClosedRange<Int> = 0 ... 3
// 专注于结果输出
_ = range.publisher
.sink { value in
print(value) // 0 1 2 3
}
// 可以获取结束状态
_ = range.publisher.sink { completion in
if completion == .finished {
print("completion")
}
} receiveValue: { element in
print("element", element)
}
assign
keyPath
assign可以通过keyPath的方式给模型赋值:
swift
class User {
var name: String = ""
}
let user = User()
let cancelable = ["吴彦祖"].publisher.assign(to: \.name, on: user)
print(user.name) // 吴彦祖
class User {
var name: String = ""
}
let user = User()
let cancelable = ["吴彦祖"].publisher.assign(to: \.name, on: user)
print(user.name) // 吴彦祖
assign 与 @Published
swift
class MyModel: ObservableObject {
@Published var id: Int = 0
}
let model = MyModel()
Just(100).assign(to: &model.$id)
print(model.id)
_ = Just(200).assign(to: \.id, on: model)
print(200)
class MyModel: ObservableObject {
@Published var id: Int = 0
}
let model = MyModel()
Just(100).assign(to: &model.$id)
print(model.id)
_ = Just(200).assign(to: \.id, on: model)
print(200)
上述写法在SwiftUI里面随处可见
https://devv.ai/zh/search?threadId=d98yqg2heiv4
@Published
修饰后,可以简化assign的操作- 上述示例代码中
ObservableObject
也可以去掉,在 SwiftUI 中,@ObservableObject
用于标记一个类,该类可以存储数据并在更改时触发视图更新。而@Published
则用于标记可观察对象中应该在更改时触发视图更新的属性。
future
swift
let future = Future<Int, Never> { promise in
// 此处可执行耗时操作
promise(.success(200))
}
let subscribe = Subscribers.Sink<Int, Never> { statue in
if statue == .finished {
print("finished")
}
} receiveValue: { value in
print(value)
}
future.subscribe(subscribe)
let future = Future<Int, Never> { promise in
// 此处可执行耗时操作
promise(.success(200))
}
let subscribe = Subscribers.Sink<Int, Never> { statue in
if statue == .finished {
print("finished")
}
} receiveValue: { value in
print(value)
}
future.subscribe(subscribe)
operator
swift
let publisher = Just(5)
let tranform = Publishers.Map<Just<Int>, String>.init(upstream: publisher) { value in
"字符串值:\(value)"
}
let subscribe = Subscribers.Sink<String, Never>.init { _ in
} receiveValue: { value in
print(value) // 字符串值:5
}
tranform.subscribe(subscribe)
// 不声明`subscribe`,直接使用也可以
// tranform.sink { value in
// print(value)
// }
let publisher = Just(5)
let tranform = Publishers.Map<Just<Int>, String>.init(upstream: publisher) { value in
"字符串值:\(value)"
}
let subscribe = Subscribers.Sink<String, Never>.init { _ in
} receiveValue: { value in
print(value) // 字符串值:5
}
tranform.subscribe(subscribe)
// 不声明`subscribe`,直接使用也可以
// tranform.sink { value in
// print(value)
// }
简化写法:
swift
let publisher = Just(5)
_ = publisher.map { value in
"-> String Value: \(value)"
}.sink { value in
print(value)
}
// 示例2:
let publisher = Just(5)
_ = publisher
.filter { item in
item >= 5
}
.map { value in
"-> String Value: \(value)"
}.sink { value in
print(value)
}
let publisher = Just(5)
_ = publisher.map { value in
"-> String Value: \(value)"
}.sink { value in
print(value)
}
// 示例2:
let publisher = Just(5)
_ = publisher
.filter { item in
item >= 5
}
.map { value in
"-> String Value: \(value)"
}.sink { value in
print(value)
}
CurrentValueSubject
CurrentValueSubject(value)
可以保存和发布最后的数据(来自send方法和其他发布者),可设置默认数据。 可以类比RxSwift中的BehaviorRelay
swift
let publisher = CurrentValueSubject<Int, Never>(20)
let subscribe = Subscribers.Sink<Int, Never>.init { _ in
} receiveValue: { value in
print("here: \(value)")
}
publisher.subscribe(subscribe)
var cancellables = Set<AnyCancellable>()
publisher.sink { value in
print("there", value)
}.store(in: &cancellables)
// 此处必须加 `.store(in: )` , 否则只会执行一次。 因为执行一次后就被释放,不会持续接收事件
publisher.send(21)
publisher.send(22)
//输出:
//here: 20
//there 20
//there 21
//heare: 21
//there 22
//here: 22
let publisher = CurrentValueSubject<Int, Never>(20)
let subscribe = Subscribers.Sink<Int, Never>.init { _ in
} receiveValue: { value in
print("here: \(value)")
}
publisher.subscribe(subscribe)
var cancellables = Set<AnyCancellable>()
publisher.sink { value in
print("there", value)
}.store(in: &cancellables)
// 此处必须加 `.store(in: )` , 否则只会执行一次。 因为执行一次后就被释放,不会持续接收事件
publisher.send(21)
publisher.send(22)
//输出:
//here: 20
//there 20
//there 21
//heare: 21
//there 22
//here: 22
swiftui中使用的例子:
swift
import SwiftUI
import Combine
// 创建一个CurrentValueSubject对象
class DataModel: ObservableObject {
var currentValueSubject = CurrentValueSubject<Int, Never>(0)
func updateValue(newValue: Int) {
currentValueSubject.send(newValue)
}
}
// SwiftUI视图
struct ContentView: View {
@StateObject var dataModel = DataModel()
var body: some View {
VStack {
Text("Current Value: \(dataModel.currentValueSubject.value)")
.padding()
Button("Update Value") {
dataModel.updateValue(newValue: Int.random(in: 1...100))
}
}
}
}
// 在ContentView中订阅CurrentValueSubject对象
struct ContentView_Previews: PreviewProvider {
static var previews: some View {
ContentView()
}
}
import SwiftUI
import Combine
// 创建一个CurrentValueSubject对象
class DataModel: ObservableObject {
var currentValueSubject = CurrentValueSubject<Int, Never>(0)
func updateValue(newValue: Int) {
currentValueSubject.send(newValue)
}
}
// SwiftUI视图
struct ContentView: View {
@StateObject var dataModel = DataModel()
var body: some View {
VStack {
Text("Current Value: \(dataModel.currentValueSubject.value)")
.padding()
Button("Update Value") {
dataModel.updateValue(newValue: Int.random(in: 1...100))
}
}
}
}
// 在ContentView中订阅CurrentValueSubject对象
struct ContentView_Previews: PreviewProvider {
static var previews: some View {
ContentView()
}
}
代码示例:发送失败消息以终止,再往后的消息不会收到
swift
var cancellables = Set<AnyCancellable>()
let publisher = CurrentValueSubject<Int, MyError>(20)
let subscribe = Subscribers.Sink<Int, MyError>.init { ff in
if ff == .finished {
print("finished")
} else {
print("error")
}
switch ff {
case .finished:
print("finished")
case .failure(let err):
print(err)
}
} receiveValue: { value in
print("here: \(value)")
}
publisher.subscribe(subscribe)
publisher.send(1)
publisher.send(2)
publisher.send(3)
publisher.send(completion: .failure(.uploadFailed))
publisher.send(4)
// here: 20
// here: 1
// here: 2
// here: 3
// error
// uploadFailed
var cancellables = Set<AnyCancellable>()
let publisher = CurrentValueSubject<Int, MyError>(20)
let subscribe = Subscribers.Sink<Int, MyError>.init { ff in
if ff == .finished {
print("finished")
} else {
print("error")
}
switch ff {
case .finished:
print("finished")
case .failure(let err):
print(err)
}
} receiveValue: { value in
print("here: \(value)")
}
publisher.subscribe(subscribe)
publisher.send(1)
publisher.send(2)
publisher.send(3)
publisher.send(completion: .failure(.uploadFailed))
publisher.send(4)
// here: 20
// here: 1
// here: 2
// here: 3
// error
// uploadFailed
@Published 和 CurrentValueSubject 之间还有一些区别和优势。
- 错误类型:@Published 的发布者的错误类型是 Never,而 CurrentValueSubject 可以指定错误类型。
- 使用范围:@Published 只能在类中使用,而 CurrentValueSubject 可以在任何地方使用,包括结构体和枚举。
- 订阅者行为:@Published 不能直接用作订阅者,而 CurrentValueSubject 可以直接订阅。
- 协议声明:@Published 不能在协议声明中使用,而 CurrentValueSubject 可以在协议中声明并使用。
- 设置初始值:CurrentValueSubject 可以在初始化时设置初始值,而 @Published 需要在声明时设置初始值。
总的来说,@Published 更适合简单的自动更新视图的场景
PassthroughSubject
和CurrentValueSubject的区别是没有默认值:
swift
let publisher = PassthroughSubject<Int, Never>()
// 写法1
let subscribe = Subscribers.Sink<Int, Never>.init { _ in
} receiveValue: { value in
print("here: \(value)")
}
publisher.subscribe(subscribe)
// 写法2
var cancellables = Set<AnyCancellable>()
publisher.sink { value in
print("there", value)
}.store(in: &cancellables)
publisher.send(21)
publisher.send(22)
let publisher = PassthroughSubject<Int, Never>()
// 写法1
let subscribe = Subscribers.Sink<Int, Never>.init { _ in
} receiveValue: { value in
print("here: \(value)")
}
publisher.subscribe(subscribe)
// 写法2
var cancellables = Set<AnyCancellable>()
publisher.sink { value in
print("there", value)
}.store(in: &cancellables)
publisher.send(21)
publisher.send(22)