iOS13 的发布者组合流在操作员使用调度程序后似乎没有流动。
这是我的代码:
import Foundation
import Combine
struct MyPublisher: Publisher {
typealias Output = Int
typealias Failure = Error
func receive<S>(subscriber: S) where S : Subscriber,
Failure == S.Failure,
Output == S.Input {
subscriber.receive(1)
print("called 1")
subscriber.receive(2)
print("called 2")
subscriber.receive(completion: .finished)
print("called finish")
}
}
MyPublisher()
// .receive(on: RunLoop.main) // If this line removed, it will be fine.
// .throttle(for: .milliseconds(1000), scheduler: RunLoop.main, latest: false)) // If this line removed, it will be fine.
// .debounce(for: .milliseconds(1000), scheduler: RunLoop.main)) // If this line removed, it will be fine.
// .delay(for: .milliseconds(1000), scheduler: DispatchQueue.main)) // If this line removed, it will be fine.
.print()
.sink(receiveCompletion: { completion in
switch completion {
case .finished:
print("finished")
case .failure(let error):
print("error:(error)")
}
}, receiveValue: { num in
print("(num)")
})
我预计输出是
1
2
finished
但实际输出什么都没有。
如果我不使用receive
或throttle
或debounce
或delay
.输出会很好。
是错误还是我的代码有问题?
我尝试了Playground(Xcode 11 beta3(。
订阅:
我不确定为什么它在单个线程的情况下有效,但您应该确保在subscriber
上调用received(subscription:)
。如果您不需要处理订阅者的需求,您可以使用Subscribers.empty
:
struct MyPublisher: Publisher {
typealias Output = Int
typealias Failure = Never
func receive<S>(subscriber: S) where S : Subscriber, Failure == S.Failure, Output == S.Input {
subscriber.receive(subscription: Subscriptions.empty)
_ = subscriber.receive(1)
Swift.print("called 1")
_ = subscriber.receive(2)
Swift.print("called 2")
_ = subscriber.receive(completion: .finished)
Swift.print("called finish")
}
}
任何可取消:
您应该注意到一条警告:
调用"sink(receiveCompletion:receiveValue:("的结果未使用
这应该出现,因为sink
返回一个AnyCancellable
:
func sink(receiveCompletion: @escaping ((Subscribers.Completion<Self.Failure>) -> Void), receiveValue: @escaping ((Self.Output) -> Void)) -> AnyCancellable
任何返回AnyCancellable
的内容都将在解除分配AnyCancellable
后立即被取消。
我的猜测是,如果您将其放在另一个线程上,那么当调用方法结束时,可取消将在收到订阅之前解除分配。但是当在当前线程上收到时,它似乎正在及时执行以显示订阅和输出。最有可能的是,当当前线程退出时,可取消的线程正在被释放。
使用可取消
例如:
class ImageLoader: ObservableObject {
@Published var image: UIImage?
private var cancellable: AnyCancellable?
func fetchImages() {
guard let urlString = urlString,
let url = URL(string: urlString) else { return }
cancellable = URLSession.shared.dataTaskPublisher(for: url)
.map { UIImage(data: $0.data) }
.replaceError(with: nil)
.receive(on: DispatchQueue.main)
.sink { [weak self] in self?.image = $0 }
}
}
使用下划线
可以通过下划线传递警告。我用了奈什塔回答中的例子。
例如
class ImageLoader: ObservableObject {
@Published var image: UIImage?
func fetchImages() {
guard let urlString = urlString,
let url = URL(string: urlString) else { return }
_ = URLSession.shared.dataTaskPublisher(for: url)
.map { UIImage(data: $0.data) }
.replaceError(with: nil)
.receive(on: DispatchQueue.main)
.sink { [weak self] in self?.image = $0 }
}
}