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

743 Views Asked by At

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
*/


1

There are 1 best solutions below

1
Fabio Felici On BEST ANSWER

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)")
  }