在 Swift 的 Combine 发布者中包装异步代码
Wrapping asynchronous code in Swift's Combine publisher
我有一个名为 QueryObserver
的 class,它可以随时间产生 多个结果 ,作为回调(闭包)返回。你这样使用它:
let observer = QueryObserver<ModelType>(query: query) { result in
switch result {
case .success(let value):
print("result: \(value)")
case .failure(let error):
print("error: \(error)")
}
}
(QueryObserver
实际上是 Firebase Firestore 笨拙的 query.addSnapshotListener
功能的包装器,如果您想知道的话。使用现代 Result
类型而不是具有多个可选参数的回调。)
在一个较旧的项目中,我正在使用 ReactiveKit 并且有一个扩展将所有这些变成 Signal
,就像这样:
extension QueryObserver {
public static func asSignal(query: Query) -> Signal<[T], Error> {
return Signal { observer in
let queryObserver = QueryObserver<T>(query: query) { result in
switch result {
case .success(let value):
observer.receive(value)
case .failure(let error):
if let firestoreError = error as? FirestoreError, case .noSnapshot = firestoreError {
observer.receive([])
} else {
observer.receive(completion: .failure(error))
}
}
}
return BlockDisposable {
queryObserver.stopListening()
}
}
}
}
虽然在一个全新的项目中,我正在使用 Combine 并试图重写它。到目前为止,我已经设法写了这个,但它不起作用。这是有道理的:observer
没有被任何东西保留,所以它立即被释放,没有任何反应。
extension QueryObserver {
public static func asSignal(query: Query) -> AnyPublisher<[T], Error> {
let signal = PassthroughSubject<[T], Error>()
let observer = QueryObserver<T>(query: query) { result in
switch result {
case .success(let value):
print("SUCCESS!")
signal.send(value)
case .failure(let error):
if let firestoreError = error as? FirestoreError, case .noSnapshot = firestoreError {
signal.send([])
} else {
signal.send(completion: .failure(error))
}
}
}
return signal.eraseToAnyPublisher()
}
}
如何使用 Combine 版本?如何包装现有的异步代码?我发现的唯一示例使用 Future
进行一次性回调,但随着时间的推移我正在处理多个值。
基本上我正在寻找 this 的 ReactiveKit-to-Combine 版本。
查看 https://github.com/DeclarativeHub/ReactiveKit/issues/251#issuecomment-575907641 一个方便的组合版本的信号,像这样使用:
let signal = Signal<Int, TestError> { subscriber in
subscriber.receive(1)
subscriber.receive(2)
subscriber.receive(completion: .finished)
return Combine.AnyCancellable {
print("Cancelled")
}
}
我有一个名为 QueryObserver
的 class,它可以随时间产生 多个结果 ,作为回调(闭包)返回。你这样使用它:
let observer = QueryObserver<ModelType>(query: query) { result in
switch result {
case .success(let value):
print("result: \(value)")
case .failure(let error):
print("error: \(error)")
}
}
(QueryObserver
实际上是 Firebase Firestore 笨拙的 query.addSnapshotListener
功能的包装器,如果您想知道的话。使用现代 Result
类型而不是具有多个可选参数的回调。)
在一个较旧的项目中,我正在使用 ReactiveKit 并且有一个扩展将所有这些变成 Signal
,就像这样:
extension QueryObserver {
public static func asSignal(query: Query) -> Signal<[T], Error> {
return Signal { observer in
let queryObserver = QueryObserver<T>(query: query) { result in
switch result {
case .success(let value):
observer.receive(value)
case .failure(let error):
if let firestoreError = error as? FirestoreError, case .noSnapshot = firestoreError {
observer.receive([])
} else {
observer.receive(completion: .failure(error))
}
}
}
return BlockDisposable {
queryObserver.stopListening()
}
}
}
}
虽然在一个全新的项目中,我正在使用 Combine 并试图重写它。到目前为止,我已经设法写了这个,但它不起作用。这是有道理的:observer
没有被任何东西保留,所以它立即被释放,没有任何反应。
extension QueryObserver {
public static func asSignal(query: Query) -> AnyPublisher<[T], Error> {
let signal = PassthroughSubject<[T], Error>()
let observer = QueryObserver<T>(query: query) { result in
switch result {
case .success(let value):
print("SUCCESS!")
signal.send(value)
case .failure(let error):
if let firestoreError = error as? FirestoreError, case .noSnapshot = firestoreError {
signal.send([])
} else {
signal.send(completion: .failure(error))
}
}
}
return signal.eraseToAnyPublisher()
}
}
如何使用 Combine 版本?如何包装现有的异步代码?我发现的唯一示例使用 Future
进行一次性回调,但随着时间的推移我正在处理多个值。
基本上我正在寻找 this 的 ReactiveKit-to-Combine 版本。
查看 https://github.com/DeclarativeHub/ReactiveKit/issues/251#issuecomment-575907641 一个方便的组合版本的信号,像这样使用:
let signal = Signal<Int, TestError> { subscriber in
subscriber.receive(1)
subscriber.receive(2)
subscriber.receive(completion: .finished)
return Combine.AnyCancellable {
print("Cancelled")
}
}