stevenpcurtis
stevenpcurtis

Reputation: 2001

Forward object using Combine

In order to update a view, I want to forward the view from my ViewController to the ViewModel by forwarding it.

Something like the following:

viewModel.labelViewModel.subscribe(forward: labelView) { labelView, model in labelView.update(with: model) }

but using Combine.

So how can I return the observer with the observable?

In the ViewController I'm trying:

viewModel.$labelModel.sink { lab in
    print("Value: \(lab?.1.text)")            
}.store(in: &subscriptions)

with the label in the ViewModel:

@Published private(set) var labelModel: (Label, Label.Model)?

but what I want to do is actually return the same label in the sink as is subscribing from the ViewController.

Is this possible?

Upvotes: 1

Views: 181

Answers (1)

Daniel T.
Daniel T.

Reputation: 33978

You could do it with something like this:

extension Publisher {
    func withUnretained<Object: AnyObject>(_ obj: Object) -> AnyPublisher<(Object, Output), Error> {
        return tryMap { [weak obj] element -> (Object, Output) in
            guard let obj = obj else { throw UnretainedError.failedRetaining }
            return (obj, element)
        }
        .eraseToAnyPublisher()
    }
}

enum UnretainedError: Swift.Error {
    case failedRetaining
}

Which would allow you to do:

$labelModel
    .withUnretained(label)
    .sink { (completion) in
        if case .failure = completion {
            print("oops!")
        }
    } receiveValue: { (label, text) in
        label.text = text
    }
    .store(in: &subscriptions)

But why do all that when you could just do this?

$labelModel
    .sink { [label] text in
        label?.text = text
    }
    .store(in: &subscriptions)

Upvotes: 1

Related Questions