Reputation: 1151
I have a publisher when the sink, scans for a list of wifi. I only want to scan for about 10 seconds and stop.
Is there a way to do this within the publisher chain of calls?
Upvotes: 7
Views: 3370
Reputation: 33967
This operator will do the trick.
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($0) })
Upvotes: 9
Reputation: 32817
You can use the timeout() operator:
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: \($0), at: \(Date())") },
receiveValue: { print("wifi: \($0)") }
)
If, however your publisher keeps regularly emitting events, and you just want to stop it after an amount of time passes, then Daniel's answer is probably the way to go.
Nonetheless, I'll add a solution on my own, via a Publisher
extension that uses timeout()
and scan()
:
extension Publisher {
func stopAfter(_ interval: TimeInterval) -> AnyPublisher<Output, Failure> {
self
.timeout(.seconds(interval), scheduler: DispatchQueue.main)
.scan((Date()+interval, nil)) { ($0.0, $1) }
.prefix(while: { Date() < $0.0 })
.map { $0.1! }
.eraseToAnyPublisher()
}
}
The above publisher will carry the timeout date, and once that date is reached, it will stop. The map
is needed to discard the extra Date
carried along the items.
Usage:
wifiListPublisher.stopAfter(10)
.sink(...)
Upvotes: 3