Swift Combine: Turn a Publisher into a Read-Only Currentvaluesubject

Swift Combine: turn a publisher into a read-only CurrentValueSubject

Why don't you simply keep the @Published property public, while making its setter private? That should suit your requirements perfectly while also keeping your code minimal and clean.

class ViewModel {
@Published public private(set) var models = ["hello", "world"]
}

let viewModel = ViewModel()
viewModel.$models.sink { print($0) }

How to convert a publisher to a CurrentValueSubject?

You can't convert publishers to CurrentValueSubject at will because it's a very specific type of publisher. Ask yourself whether you really need the type of myPublisher to be CurrentValueSubject<Void, Never> or if an AnyPublisher<Void, Never> would do.

var myPublisher: AnyPublisher <Void, Never> {
Just(()).eraseToAnyPublisher()
}

Alternatively, if all you're trying to do is create an instance of CurrentValueSubject that has () as its initial value you could use this:

var myPublisher: CurrentValueSubject<Void, Never> {
CurrentValueSubject<Void, Never>(())
}

How to use Combine's CurrentValueSubject and access it in a SwiftUI View?

I think your question shows that you need to learn a bit more the foundational principle behind SwiftUI, and behind Combine (that statement about "CurrentValueSubject vs regular Publisher" was quite wrong).

All you need here is to expose a @Published property on your WorkoutManager, and set it to the value that you want, when needed:

class WorkoutManager: NSObject, HKWorkoutSessionDelegate, HKLiveWorkoutBuilderDelegate, ObservableObject  {

@Published var finishedWorkoutTotalEnergyBurned = 0.0

func stopWorkout() {
finishedWorkoutTotalEnergyBurned = unwrappedWorkout.totalEnergyBurned!.doubleValue(for: .kilocalorie())
}
}
struct SummaryView: View {

@StateObject var workoutManager = WorkoutManager()

var body: some View {
Text("\(workoutManager.finishedWorkoutTotalEnergyBurned)")
.navigationBarHidden(true)
}
}

@Published does use a Combine publisher under the hood, which in combination with @StateObject cause the view to update. But all you need to reason about here, is how and when to set these properties - and the view will update automatically. In the case you showed, there's likely no need to use a publisher directly.

Swift Combine - Multiple Observable (CurrentValueSubject or PassthroughSubject) into one but wait for update from all

Zip3 seems to be what you are looking for:

Publishers
.Zip3(var1, var2, var3)
.sink(receivedValue: { var1, var2, var3 in
print("Printed!")
})
.store(in: &subscriptions)

From the docs of zip:

Use zip(_:_:) to return a new publisher that combines the elements from two additional publishers to publish a tuple to the downstream. The returned publisher waits until all three publishers have emitted an event, then delivers the oldest unconsumed event from each publisher as a tuple to the subscriber.

See a visualisation on RxMarbles!

Create a CurrentValueSubject from another CurrentValueSubject

I would just have the second publisher be a subscriber to the first publisher. Example:

let pub1 = CurrentValueSubject<String,Never>("howdy")
lazy var pub2 : AnyPublisher<String,Never> = {
self.pub1.eraseToAnyPublisher()
}()

Example of usage:

    pub1.sink {print($0)}.store(in: &storage)
pub2.sink {print($0)}.store(in: &storage)
delay(1) {
self.pub1.send("hey")
delay(2) {
self.pub1.send("ho")
}
}

Output:

howdy
howdy
[delay]
hey
hey
[delay]
ho
ho

So both publishers are giving out the same value, which seems to be what you want.

Difference between CurrentValueSubject and @Published

@Published is just a quick way to use CurrentValueSubject a little neater. When I debug one of my apps and look at the type returned by $paramName , it's actually just a CurrentValueSubject:

po self.$books
▿ Publisher
▿ subject : <CurrentValueSubject<Array<Book>, Never>: 0x6000034b8910>

I guess one benefit of using CurrentValueSubject instead of @Published may be to allow you to use the error type?

Note: Despite being a CurrentValueSubject right now I'd never rely on that assumption.



Related Topics



Leave a reply



Submit