Reputation: 1
I have a ObservableObject-Class which inside this class, I got a published var with name of persones! I do initialize it with some data called: allData.
Then I try to update my allData with action of a Button, and this action apply the wanted update to my allData, but my published var has no idea, that this data got updated!
How we can make published see the new updated allData?
struct PersonData: Identifiable {
let id = UUID()
var name: String
}
var allData = [PersonData(name: "Bob"), PersonData(name: "Nik"), PersonData(name: "Tak"), PersonData(name: "Sed"), PersonData(name: "Ted")]
class PersonDataModel: ObservableObject {
@Published var persones: [PersonData] = allData
}
struct ContentView: View {
@StateObject var personDataModel = PersonDataModel()
var body: some View {
VStack
{
Button("update allData") { allData = [PersonData(name: "Bob")] }
HStack
{
ForEach(personDataModel.persones) { person in Text(person.name) }
}
}
.font(Font.title)
}
}
PS: I don´t want use .onChange or other things for this, I would like this happens internally in my class.
Also I know I can use down code for this work, but that is not the answer
personDataModel.persones = [PersonData(name: "Bob")]
Upvotes: 1
Views: 271
Reputation: 54516
Having a top-level property (outside of any class or struct) is probably not a good idea. I don't see the whole picture, but it looks like your app needs a global state (e.g., a @StateObject
initialised on the App
level). Consider this answer:
If you really need to observe your array, you need to make it observable.
One option is to use CurrentValueSubject from the Combine
framework:
var persons = ["Bob", "Nik", "Tak", "Sed", "Ted"].map(PersonData.init)
var allData = CurrentValueSubject<[PersonData], Never>(persons)
class PersonDataModel: ObservableObject {
@Published var persones: [PersonData] = allData.value
private var cancellables = Set<AnyCancellable>()
init() {
allData
.sink { [weak self] in
self?.persones = $0
}
.store(in: &cancellables)
}
}
struct ContentView: View {
@StateObject var personDataModel = PersonDataModel()
var body: some View {
VStack {
Button("update allData") {
allData.send([PersonData(name: "Bob")])
}
HStack {
ForEach(personDataModel.persones) { person in
Text(person.name)
}
}
}
.font(Font.title)
}
}
Upvotes: 1
Reputation: 2842
I think you're doing something wrong.
if you want to update all your views, you have to pass the same object with @EnviromentObject
.
I don't know your storage method (JSON, CORE DATA, iCloud) but the correct approach is to update directly the model
class PersonDataModel: ObservableObject
{
@Published var persones: [PersonData] = loadFromJSON //one func that is loading your object stored as JSON file
func updateAllData() {
storeToJSON(persones) //one func that is storing your object as JSON file
}
}
struct ContentView: View {
@StateObject var personDataModel = PersonDataModel()
var body: some View {
VStack
{
Button("update allData") {
self.personDataModel.persones = [PersonData(name: "Bob")]
}
HStack
{
ForEach(personDataModel.persones) { person in Text(person.name) }
}
}
.font(Font.title)
.onChange($personDataModel.persones) {
persones.updateAllData()
}
}
}
Upvotes: 0
Reputation: 257749
The allData
is copied into persones
at initialization time, so changing it afterwards does nothing to personDataModel
. After StateObject
created you have to work with it, like
Button("update allData") {
self.personDataModel.persones = [PersonData(name: "Bob")]
}
Upvotes: 0