Jon Vogel
Jon Vogel

Reputation: 5644

Combine assign(to: on:) another publisher

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

Answers (2)

rob mayoff
rob mayoff

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

LuLuGaGa
LuLuGaGa

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

Related Questions