web-dev-qa-db-ja.com

入れ子になったObservableObjectにバインドするようにSwiftUIビューに指示する方法

appModelというEnvironmentObjectを取り込むSwiftUIビューがあります。次に、bodyメソッドで値appModel.submodel.countを読み取ります。これにより、ビューが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に渡すことでこれを修正できますが、可能であればそうしないようにします。

16
rjkaplan

ネストされたモデルは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()
        }
    } 
}

基本的にAppModelSubmodelからイベントをキャッチし、ビューにさらに送信します

編集:

SubModelをクラスにする必要がない場合は、次のようなことを試すことができます。

struct Submodel{
    var count = 0
}

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

3つのViewModelはすべて通信および更新できます

// 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
}

ソリン、コンバインソリューションをありがとう。

1