Наблюдение за @опубликованной переменной из другого объекта

#swift #combine

#swift #объединить

Вопрос:

Я пытаюсь заставить один объект прослушивать изменения в свойстве другого объекта. У меня это работает, как показано ниже, но я бы предпочел, чтобы наблюдающий объект ничего не знал о модели, только о свойстве.

 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")
        }
    }
}
  

На данный момент я начинаю наблюдать за model.items следующим образом — что работает:

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

К сожалению, я не могу понять, что требуется в качестве параметра для метода observeItems, чтобы он работал, ничего не зная о модели — вот так:

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

А затем назовите это следующим образом:

 itemUser.observeItems(XXX: model.$items)
  

Кто-нибудь может объяснить, что мне нужно сделать? Спасибо!

Ответ №1:

Вы можете просто принять publisher в качестве параметра, если вам все равно, откуда берется значение.

В вашем очень конкретном случае это может быть:

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

Но это может быть слишком ограничительным — почему только этот конкретный издатель? В принципе, вас не должно волновать, кто является издателем — все, что вас волнует, это выходное значение и тип ошибки. Вы можете сделать его универсальным для любого издателя, при условии, что его вывод [Int] и сбой Never (как у @Published одного):

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

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

Использование было бы примерно таким:

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

Комментарии:

1. Большое спасибо новому разработчику — работает отлично, и я бы никогда этого не понял.