swiftcombineprefixfrpcollect

Swift Combine collect values while a condition is true but also one more time after it's true


Sorry for the awkward phrasing. Seeing the example below will probably answer all your questions.

So the scenario is that I want to observe a stream of values and collect all the values up until I witness a value. But I also want that value I've witnessed to be added to the colleciton.

So in the example, I'm showing I missing the value 'lastPage'

I made this in a playground in XCode 13.4.1

import Foundation
import Combine

var subj = PassthroughSubject<String, Never>()

let cancel = subj.prefix{
    $0 != "LastPage"
}
.collect(.byTime(DispatchQueue(label: "Test"), .seconds(3)))
.sink {
    print("complete: \($0)")
} receiveValue: {
    print("received: \($0)")
}

print("start")

let strings = [
    "!@#$",
    "ZXCV",
    "LastPage",
    "ASDF",
    "JKL:"
]

for i in (0..<strings.count) {
    DispatchQueue.main.asyncAfter(deadline: .now() + .seconds(i)) {
        let s = strings[i]
        print("sending \(s)")
        subj.send(s)
    }
}

/* this prints the following
start
sending !@#$
sending ZXCV
sending LastPage
received: ["!@#$", "ZXCV"] <<<< I want this array to include 'LastPage'
complete: finished
sending ASDF
*/



Solution

  • You can use scan and first(where:):

    let cancel = subj
      .scan([String]()) { $0 + [$1] }
      .first { $0.last == "LastPage" }
      .sink {
        print("complete: \($0)")
      } receiveValue: {
        print("received: \($0)")
      }