Peter
Peter

Reputation: 922

Observing a @Published var from another Object

I am trying to get one object to listen to changes in the property of another object. I have it working as shown below, but I would prefer the observing object knew nothing of the Model, just the property.

class Model : ObservableObject{
    @Published var items: [Int] = []
}

class ObjectUsingItems{
    var itemObserver: AnyCancellable?
    var items: [Int] = []
    
    func observeItems(model: Model){
        itemObserver = model.$items
            .sink{ newItems in
                self.items = newItems
                print("New Items")
        }
    }
}

At the moment I begin observing the model.items as follows - which works:

let model = Model()
let itemUser = ObjectUsingItems()
        
itemUser.observeItems(model: model)
model.items.append(1) // itemUser sees changes

Unfortunately I can’t seem to figure out just what is required as the parameter to the observeItems method so that it works without knowing anything about the Model - like this:

class ObjectUsingItems{
    var itemObserver: AnyCancellable?
    var items: [Int] = []
    
    func observeItems(propertyToObserve: WhatGoesHere?){
        itemObserver = propertyToObserve
            .sink{ newItems in
                // etc.
        }
    }
}

And then call it like so:

itemUser.observeItems(XXX: model.$items)

Can anyone explain what I need to do? Thanks!

Upvotes: 7

Views: 3563

Answers (1)

New Dev
New Dev

Reputation: 49590

You can just accept a publisher as a parameter, if you don't care where the value comes from.

In your very specific case, it could be:

func observeItems(propertyToObserve: Published<[Int]>.Publisher) {
   itemObserver = propertyToObserve
                     .sink { self.items = $0 }
}

But this might be too restrictive - why only this specific publisher? In principle, you shouldn't care what the publisher is - all you care about is the output value and error type. You can make it generic to any publisher, so long as its Output is [Int] and Failure is Never (like that of the @Published one):

func observeItems<P: Publisher>(propertyToObserve: P) 
   where P.Output == [Int], P.Failure == Never {

   itemObserver = propertyToObserve
                     .sink { self.items = $0 }
} 

The usage would be something like this:

let model = Model()
let itemUser = ObjectUsingItems()
        
itemUser.observeItems(propertyToObserve: model.$items)

Upvotes: 6

Related Questions