Как заставить представления SwiftUI связываться с вложенными объектами ObservableObject

18

У меня есть представление SwiftUI, которое принимает в EnvironmentObject называется appModel. Затем он читает значение appModel.submodel.countв своем bodyметоде. Я ожидаю , что это связать мой взгляд на собственность countна submodelтак , что она повторно делает , когда обновление свойств, но это , кажется, не бывает.

Это ошибка? И если нет, то каким является идиоматический способ привязки представлений к вложенным свойствам объектов среды в SwiftUI?

В частности, моя модель выглядит так ...

class Submodel: ObservableObject {
  @Published var count = 0
}

class AppModel: ObservableObject {
  @Published var submodel: Submodel = Submodel()
}

И мой взгляд выглядит так ...

struct ContentView: View {
  @EnvironmentObject var appModel: AppModel

  var body: some View {
    Text("Count: \(appModel.submodel.count)")
      .onTapGesture {
        self.appModel.submodel.count += 1
      }
  }
}

Когда я запускаю приложение и нажимаю на метку, countсвойство увеличивается, но метка не обновляется.

Я могу исправить это, передав в appModel.submodelкачестве свойства ContentView, но я хотел бы избежать этого, если это возможно.

rjkaplan
источник
Я также создаю свое приложение, как это. У меня обычно есть глобальный объект App в прошлой разработке приложения. Кто-нибудь еще думает, что такой дизайн суперкласса «App» как переменной среды станет стандартной практикой? Я также рассматривал возможность использования нескольких EnvironmentObjects, но это было сложно поддерживать.
Михаил Озерянский

Ответы:

22

Вложенные модели еще не работают в SwiftUI, но вы можете сделать что-то подобное

class Submodel: ObservableObject {
    @Published var count = 0
}

class AppModel: ObservableObject {
    @Published var submodel: Submodel = Submodel()

    var anyCancellable: AnyCancellable? = nil

    init() {
        anyCancellable = submodel.objectWillChange.sink { (_) in
            self.objectWillChange.send()
        }
    } 
}

В основном, вы AppModelловите событие Submodelи отправляете его дальше в View.

Редактировать:

Если вам не нужно SubModelбыть классом, то вы можете попробовать что-то вроде этого:

struct Submodel{
    var count = 0
}

class AppModel: ObservableObject {
    @Published var submodel: Submodel = Submodel()
}
Сорин Лика
источник
Спасибо, это полезно! Когда вы говорите «Вложенные модели еще не работают в SwiftUI», вы точно знаете, что они запланированы?
rjkaplan
Я не уверен, но, по моему мнению, это должно сработать, я также использую что-то похожее в моем проекте, так что, если я найду лучший подход, я приду с правкой
Сорин Лика
@SorinLica Должен Submodelбыть ObservableObject тип?
Фархан Амджад
Работает! Отличное решение!
Md Shahed Hossain
1

Все три ViewModels могут общаться и обновлять

// First ViewModel
class FirstViewModel: ObservableObject {
var facadeViewModel: FacadeViewModels

facadeViewModel.firstViewModelUpdateSecondViewModel()
}

// Second ViewModel
class SecondViewModel: ObservableObject {

}

// FacadeViewModels Combine Both 

import Combine // so you can update thru nested Observable Objects

class FacadeViewModels: ObservableObject { 
lazy var firstViewModel: FirstViewModel = FirstViewModel(facadeViewModel: self)
  @Published var secondViewModel = secondViewModel()
}

var anyCancellable = Set<AnyCancellable>()

init() {
firstViewModel.objectWillChange.sink {
            self.objectWillChange.send()
        }.store(in: &anyCancellable)

secondViewModel.objectWillChange.sink {
            self.objectWillChange.send()
        }.store(in: &anyCancellable)
}

func firstViewModelUpdateSecondViewModel() {
     //Change something on secondViewModel
secondViewModel
}

Спасибо Сорин за объединенное решение.

здравко здравкин
источник
Не могли бы вы обновить код? в нем много ошибок компилятора
DevB2F
-2

Похоже, ошибка. Когда я обновляю xcode до последней версии, он работает правильно при привязке к вложенным объектам ObservableObjects.

norains
источник
Можете ли вы уточнить, какая версия xcode у вас сейчас работает? Я в настоящее время имею Xcode 11.0 и испытываю эту проблему. У меня были проблемы с обновлением до 11.1, оно не пройдет, как завершено на 80%.
Михаил Озерянский