Bagaimana cara memberitahu pandangan SwiftUI untuk mengikat ke ObservableObjects yang bersarang

18

Saya memiliki tampilan SwiftUI yang menggunakan EnvironmentObject yang dipanggil appModel. Kemudian membaca nilai appModel.submodel.countdalam bodymetodenya. Saya berharap ini untuk mengikat pandangan saya ke properti countdi submodelsehingga membuat kembali ketika properti diperbarui, tetapi ini tampaknya tidak terjadi.

Apakah ini bug? Dan jika tidak, apa cara idiomatis untuk memiliki pandangan mengikat properti bersarang objek lingkungan di SwiftUI?

Secara khusus, model saya terlihat seperti ini ...

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

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

Dan pandangan saya terlihat seperti ini ...

struct ContentView: View {
  @EnvironmentObject var appModel: AppModel

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

Ketika saya menjalankan aplikasi dan mengklik label, countproperti bertambah tetapi label tidak memperbarui.

Saya dapat memperbaikinya dengan melewatinya appModel.submodelsebagai properti ContentView, tetapi saya ingin menghindari melakukannya jika memungkinkan.

rjkaplan
sumber
Saya juga merancang aplikasi saya seperti ini. Saya biasanya memiliki objek Aplikasi global dalam pengembangan aplikasi sebelumnya. Apakah ada orang lain yang menganggap desain kelas "App" super ini sebagai variabel lingkungan akan menjadi praktik standar? Saya juga mempertimbangkan untuk menggunakan beberapa EnvironmentObjects tapi itu sulit dipertahankan.
Michael Ozeryansky

Jawaban:

22

Model bersarang belum berfungsi di SwiftUI, tetapi Anda dapat melakukan sesuatu seperti ini

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

Pada dasarnya milikmu AppModel menangkap acara dari Submodeldan mengirimkannya lebih jauh ke View

Edit:

Jika Anda tidak perlu SubModelmenjadi kelas, maka Anda dapat mencoba sesuatu seperti ini:

struct Submodel{
    var count = 0
}

class AppModel: ObservableObject {
    @Published var submodel: Submodel = Submodel()
}
Sorin Lica
sumber
Terima kasih, ini sangat membantu! Ketika Anda mengatakan "Model bersarang belum berfungsi di SwiftUI", apakah Anda tahu pasti bahwa itu direncanakan?
rjkaplan
Saya tidak yakin, tetapi menurut saya itu harus berhasil, saya juga menggunakan sesuatu yang serupa di proj saya, jadi jika saya akan menemukan pendekatan yang lebih baik saya akan datang dengan suntingan
Sorin Lica
@SorinLica Harus Submodelmenjadi ObservableObject jenis?
Farhan Amjad
Bekerja! Solusi yang luar biasa!
Md Shahed Hossain
1

Ketiga ViewModels dapat berkomunikasi dan memperbarui

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

Terima kasih Sorin untuk solusi Combine.

zdravko zdravkin
sumber
Bisakah Anda memperbarui kode? ia memiliki banyak kesalahan penyusun
DevB2F
-2

Sepertinya bug. Ketika saya memperbarui xcode ke versi terbaru, itu berfungsi dengan benar saat mengikat ke ObservableObjects bersarang

norain
sumber
Bisakah Anda menjelaskan versi xcode apa yang sedang Anda gunakan? Saat ini saya memiliki Xcode 11.0 dan mengalami masalah ini. Saya mengalami kesulitan untuk meningkatkan ke 11.1, itu tidak akan selesai seperti 80% selesai.
Michael Ozeryansky