您如何 运行 一个 Swift 合并发布者一段时间?
How do you run a Swift Combine Publisher for a certain amount of time?
我有一个publisher当sink,扫描一个wifi列表。我只想扫描大约 10 秒然后停止。
有没有办法在发布者调用链中执行此操作?
这个运算符可以解决问题。
import PlaygroundSupport
import Foundation
import Combine
let page = PlaygroundPage.current
page.needsIndefiniteExecution = true
extension Publisher {
func stopAfter<S>(_ interval: S.SchedulerTimeType.Stride, tolerance: S.SchedulerTimeType.Stride? = nil, scheduler: S, options: S.SchedulerOptions? = nil) -> AnyPublisher<Output, Failure> where S: Scheduler {
prefix(untilOutputFrom: Just(()).delay(for: interval, tolerance: tolerance, scheduler: scheduler, options: nil))
.eraseToAnyPublisher()
}
}
let source = Timer.publish(every: 1, tolerance: nil, on: RunLoop.main, in: .default, options: nil)
.autoconnect()
.eraseToAnyPublisher()
let cancellable = source
.stopAfter(10, scheduler: DispatchQueue.main)
.sink(receiveValue: { print([=10=]) })
您可以使用 timeout() 运算符:
Terminates publishing if the upstream publisher exceeds the specified time interval without producing an element.
wifiScannerPublisher
.timeout(.seconds(waitTime), scheduler: DispatchQueue.main, options: nil, customError:nil)
.sink(
receiveCompletion: { print("completion: \([=10=]), at: \(Date())") },
receiveValue: { print("wifi: \([=10=])") }
)
但是,如果您的发布者一直定期发出事件,而您只是想在一段时间后停止它,那么 答案可能是可行的方法。
尽管如此,我将通过使用 timeout()
和 scan()
:
的 Publisher
扩展自行添加一个解决方案
extension Publisher {
func stopAfter(_ interval: TimeInterval) -> AnyPublisher<Output, Failure> {
self
.timeout(.seconds(interval), scheduler: DispatchQueue.main)
.scan((Date()+interval, nil)) { ([=11=].0, ) }
.prefix(while: { Date() < [=11=].0 })
.map { [=11=].1! }
.eraseToAnyPublisher()
}
}
以上发布者会携带超时日期,一旦到达该日期,它就会停止。需要 map
来丢弃物品中携带的额外 Date
。
用法:
wifiListPublisher.stopAfter(10)
.sink(...)
我有一个publisher当sink,扫描一个wifi列表。我只想扫描大约 10 秒然后停止。
有没有办法在发布者调用链中执行此操作?
这个运算符可以解决问题。
import PlaygroundSupport
import Foundation
import Combine
let page = PlaygroundPage.current
page.needsIndefiniteExecution = true
extension Publisher {
func stopAfter<S>(_ interval: S.SchedulerTimeType.Stride, tolerance: S.SchedulerTimeType.Stride? = nil, scheduler: S, options: S.SchedulerOptions? = nil) -> AnyPublisher<Output, Failure> where S: Scheduler {
prefix(untilOutputFrom: Just(()).delay(for: interval, tolerance: tolerance, scheduler: scheduler, options: nil))
.eraseToAnyPublisher()
}
}
let source = Timer.publish(every: 1, tolerance: nil, on: RunLoop.main, in: .default, options: nil)
.autoconnect()
.eraseToAnyPublisher()
let cancellable = source
.stopAfter(10, scheduler: DispatchQueue.main)
.sink(receiveValue: { print([=10=]) })
您可以使用 timeout() 运算符:
Terminates publishing if the upstream publisher exceeds the specified time interval without producing an element.
wifiScannerPublisher
.timeout(.seconds(waitTime), scheduler: DispatchQueue.main, options: nil, customError:nil)
.sink(
receiveCompletion: { print("completion: \([=10=]), at: \(Date())") },
receiveValue: { print("wifi: \([=10=])") }
)
但是,如果您的发布者一直定期发出事件,而您只是想在一段时间后停止它,那么
尽管如此,我将通过使用 timeout()
和 scan()
:
Publisher
扩展自行添加一个解决方案
extension Publisher {
func stopAfter(_ interval: TimeInterval) -> AnyPublisher<Output, Failure> {
self
.timeout(.seconds(interval), scheduler: DispatchQueue.main)
.scan((Date()+interval, nil)) { ([=11=].0, ) }
.prefix(while: { Date() < [=11=].0 })
.map { [=11=].1! }
.eraseToAnyPublisher()
}
}
以上发布者会携带超时日期,一旦到达该日期,它就会停止。需要 map
来丢弃物品中携带的额外 Date
。
用法:
wifiListPublisher.stopAfter(10)
.sink(...)