所以我想收集價值,直到我看到最后一頁,但如果最后一頁永遠不會出現,我想發送我們所擁有的,給定時間限制。
我有辦法做到這一點,但它似乎相當浪費。我將使用它來制作可能具有數十萬個值的集合,因此更節省空間的方法將是首選。
您可以將以下內容復制并粘貼到游樂場
import UIKit
import Foundation
import Combine
var subj = PassthroughSubject<String, Never>()
let queue = DispatchQueue(label: "Test")
let collectForTime = subj
.collect(.byTime(queue, .seconds(10)))
let collectUntilLast = subj
.scan([String]()) { $0 [$1] }
.first { $0.last == "LastPage" }
// whichever happens first
let cancel = collectForTime.merge(with: collectUntilLast)
.first()
.sink {
print("complete1: \($0)")
} receiveValue: {
print("received1: \($0)")
}
print("start")
let strings = [
"!@#$",
"ZXCV",
"LastPage", // comment this line to test to see what happens if no last page is sent
"ASDF",
"JKL:"
]
// if the last page is present then the items 0..<3 will be sent
// if there's no last page then send what we have
// the main thing is that the system is not just sitting there waiting for a last page that never comes.
for i in (0..<strings.count) {
DispatchQueue.main.asyncAfter(deadline: .now() .seconds(i)) {
let s = strings[i]
print("sending \(s)")
subj.send(s)
}
}
uj5u.com熱心網友回復:
更新
在操場上玩了更多之后,我認為您需要的只是:
subj
.prefix { $0 != "LastPage" }
.append("LastPage")
.collect(.byTime(DispatchQueue.main, .seconds(10)))
我不會使用collect,因為在引擎蓋下它基本上在做同樣的事情scan,你只需要first閉包中的另一個條件,例如:.first { $0.last == "LastPage" || timedOut }在超時的情況下發出收集的專案。
很遺憾collect沒有提供您需要的 API,但我們可以創建它的另一個版本。這個想法是combineLatest輸出一個在截止日期之后scan發出的流Bool(實際上我們也需要false最初發出combineLatest以啟動)和||這個額外的變數內部filter條件。
這是代碼:
extension Publisher {
func collect<S: Scheduler>(
timeoutAfter interval: S.SchedulerTimeType.Stride,
scheduler: S,
orWhere predicate: @escaping ([Output]) -> Bool
) -> AnyPublisher<[Output], Failure> {
scan([Output]()) { $0 [$1] }
.combineLatest(
Just(true)
.delay(for: interval, scheduler: scheduler)
.prepend(false)
.setFailureType(to: Failure.self)
)
.first { predicate($0) || $1 }
.map(\.0)
.eraseToAnyPublisher()
}
}
let subj = PassthroughSubject<String, Never>()
let cancel = subj
.collect(
timeoutAfter: .seconds(10),
scheduler: DispatchQueue.main,
orWhere: { $0.last == "LastPage" }
)
.print()
.sink { _ in }
uj5u.com熱心網友回復:
我對你的技術做了一個小改動
import Foundation
import Combine
var subj = PassthroughSubject<String, Never>()
let lastOrTimeout = subj
.timeout(.seconds(10), scheduler: RunLoop.main )
.print("watchdog")
.first { $0 == "LastPage" }
.append(Just("Done"))
let cancel = subj
.prefix(untilOutputFrom: lastOrTimeout)
.print("main_publisher")
.collect()
.sink {
print("complete1: \($0)")
} receiveValue: {
print("received1: \($0)")
}
print("start")
let strings = [
"!@#$",
"ZXCV",
"LastPage", // comment this line to test to see what happens if no last page is sent
"ASDF",
"JKL:"
]
// if the last page is present then the items 0..<3 will be sent
// if there's no last page then send what we have
// the main thing is that the system is not just sitting there waiting for a last page that never comes.
strings.enumerated().forEach { index, string in
DispatchQueue.main.asyncAfter(deadline: .now() .seconds(index)) {
print("sending \(string)")
subj.send(string)
}
}
lastOrTimeoutLastPage由于超時(并發出Done) ,當它看到或完成時將發出一個值。
主管道收集值,直到看門狗發布者發出一個值并收集所有結果。
轉載請註明出處,本文鏈接:https://www.uj5u.com/net/518622.html
標籤:迅速反应式编程结合出版商
上一篇:處理視圖加載時間并列印結果
