Reputation: 5644
Here is a simple "Download" class to illustrate what I want to do.
class Download {
public var progress: CurrentValueSubject<Double, Never> = CurrentValueSubject<Double, Never>(0)
var subscriptions: Set<AnyCancellable> = []
func start(task: URLSessionTask) {
task.resume()
task.progress.publisher(for: \.fractionCompleted).sink { [weak self] (newProgress) in
self?.progress.send(newProgress)
}.store(in: &subscriptions)
}
}
I would like to be able to "re-publish" the progress property observer publisher to my current value subject. As you can see I currently subscribe using the .sink
function and then just call the CurrentValueSubject
publisher directly.
I would like to be able to use something like the .assign(to:, on:)
operator like this.
task.progress.publisher(for: \.fractionCompleted).assign(to: \.progress, on: self)
However, that will not work nor will the .assign(to:)
operator that seems to be reserved for "re-publishing" on a SwiftUI @Published
property. Why is Combine not living up to it's name here?
Upvotes: 9
Views: 11438
Reputation: 385998
Because CurrentValueSubject
is a class
, you can use it as the object
argument of assign(to:on:)
. This way, there is no memory leak:
class Download {
public let progress: CurrentValueSubject<Double, Never> = .init(0)
var subscriptions: [AnyCancellable] = []
func start(task: URLSessionTask) {
task.resume()
task.progress
.publisher(for: \.fractionCompleted)
.assign(to: \.value, on: progress)
.store(in: &subscriptions)
}
}
Upvotes: 15
Reputation: 14418
You need to assign to the value of the subject, not the subject itself. It is worth noting though that assign(to: ..., on: self)
leads to a memory leak 🤷🏻♀️.
func start(task: URLSessionTask) {
task.resume()
task.progress
.publisher(for: \.fractionCompleted)
.assign(to: \.progress.value, on: self)
.store(in: &subscriptions)
}
Upvotes: 4