Combine -- 响应式和指令式的桥梁
2021-02-23 本文已影响0人
jancywen
Apple 平台的开发,包括系统级别的 API 和大多数的第三方框架,也都是按照指令式编程的方式来编写的。想要在 Combine 的响应式框架中使用这些指令式的 API,我们需要一些手段来把这些命令转换为合适的 Publisher。
Future
如果订阅和值的发布是同步过程,我们可以直接用Just 将某个值 “包装” 成一个 Publisher 来提供给各类 Publisher 的合并操作
如果我们希望订阅操作和值的发布是异步行为,不在同一时间发生的话,可以使用 Future。Future 提供了一种方式,可以让我们创建一个接受未来的事件的 Publisher。
struct SampleModel {
var id: Int?
}
func sampleRequestAction(handler: @escaping(SampleModel?, Error?) -> Void) {
print("模拟延时")
DispatchQueue.global().asyncAfter(deadline: .now() + 1) {
print("延时结束返回")
handler(SampleModel(id: 5), nil)
}
}
Future<SampleModel, Error> { promise in
sampleRequestAction { (model, err) in
print("promise")
if let model = model {
promise(.success(model))
}else {
promise(.failure(err!))
}
}
}
.subscribe(on: RunLoop.main)
.sink { (complete) in
print("complete")
if case .failure(let msg) = complete {
print(msg)
}
} receiveValue: { (model) in
print("receiveValue:")
print(model.id)
}
// 模拟延时
// 延时结束返回
// promise
// receiveValue:
// Optional(5)
// complete
Future 只能为我们提供一次性 Publisher:对于提供的 promise,你只有两种选择:发送一个值并让 Publisher 正常结束,或者发送一个错误。因此,Future 只适用于那些必然会产生事件结果,且至多只会产生一个结果的场景。比如刚才看到的网络请求:它要么成功并返回数据及响应,要么直接失败并给出URLError。
subject
对于可重复的多次发生的事件,可以使用 subject
let subject = PassthroughSubject<(), Never>()
Timer.scheduledTimer(withTimeInterval: 1, repeats: true) { _ in
subject.send()
}