J’ai une incompréhension, je ne comprends pas cela :
J’ai une vue (Content) qui contient un modèle qui hérite d’ObservableObject et une autre vue (TestView) qui instancie le modèle en StateObject.
Le modèle contient une propriété « test » qui est une instance de la classe Post qui d’ailleurs hérite d’ObservableObject.
Mon modèle a une méthode nommée sobrement addItem, il ajoute un string « item » dans la propriété test ( une instance de la classe Post) du modèle.
Donc je teste mon programme, je clique sur le bouton, la fonction addItem se lance, ajout un item dans l’array sur lequel un ForEach itère et là…CE FICHU FOREACH NE SE MET PAS À JOUR
Désolé je ne touche pas à Swift mais j’ai une petite question. Tu n’utilises pas l’émulateur natif de Xcode n’est-ce pas ? Lequel utilises-tu dans ce cas et a-t-il une camera ? (au contraire des émulateur natif de Xcode)
J’ai souvent tout faux, je te prie de bien vouloir m’excuser si nécessaire, mais quand le lis ton code, je vois bien que tu déclares ton tableau de chaînes de caractère, mais je ne vois pas où tu l’initialises ? Je me trompe ? Je ne suis pas sûr qu’il suffise d’initialiser Post pour ça ?
dans TestView, tu déclares une variable « model » qui est liée à la vue StateView; quand tu mets à jour la variable « model » de la ContentView, il n’y a aucun lien avec la variable du même nom de testView
Essaie avec @Binding au lieu de @StateView; tu seras normalement obligé de rajouter le signe « $ » quand tu passeras la variable « model » de ContentView vers TestView ce qui sera le signe qu’il y a un lien entre les deux
Un commentaire qui n’a rien à voir: la syntaxe ci-dessus peut être dangereuse, puisque tes objets dans la boucle ForEach sont censés être identifiés de manière unique. Or un tableau de String peut contenir des objets qui seront considérés comme identiques, ce qui va poser problème s’il s’agit d’en modifier, supprimer, etc…
Pour commencer, ta ContentView est ta vue principale, contenant ton TestView.
C’est donc là que tu dois declarer ton @StateObject.
« State » étant la « Source Of Truth » de ta variable.
D’ailleurs, on écrit toujours :
@StateObject private var model: Model = Model()
pour l’initialiser et
@ObservedObject var model: Model
sans initialisation (on passera la référence en appelant la vue, ou avec un onAppear par example).
On ne déclare jamais un @ObservedObject de cette façon :
@ObservedObject var model: Model = Model()
Ensuite, ce serait plutôt dans ton Model que tu maintien a jour la liste des différents Posts
@Published var test: [Post] = []
avec la méthode permettant de les rajouter (ou les retirer).
Je te mets un example dans le code final :
// struct plutot que class
// Post conforme au protocole Identifiable
struct Post: Identifiable {
// Creation d'un unique id pour chaque Post (Identifiable)
let id: UUID = UUID()
// Title est par default "test" quand un Post est cree
var title: String = "test"
}
class Model: ObservableObject {
// Declaration de la liste de Post
@Published var test: [Post] = []
func addItem() {
// Ajout d'un Post a la liste avec le titre "item"
self.test.append(Post(title: "item"))
}
func addItem(title: String) {
// Une methode pour changer le title du Post (avec un TextField par example...)
self.test.append(Post(title: title))
}
func removeItem() {
// Verification que la liste n'est PAS vide
if (!test.isEmpty) {
// On enleve le dernier element de la liste
self.test.remove(at: test.count - 1)
}
}
}
struct ContentView: View {
// Declaration du Model dans la vue principale
@StateObject private var model: Model = Model()
var body: some View {
VStack {
// Affichage de TestView en passant la reference du Model
TestView(model: model)
// Je mettrais un Spacer() ici pour que les boutons soient toujours en bas de l'ecran
// ainsi qu'une ScrollView autour du TestView pour ne pas que les boutons disparaissent
// une fois la vue est remplie de VStack dans le ForEach...
HStack(spacing: 50.0) {
Button {
// Appel de la methode addItem()
self.model.addItem()
} label: {
Text("Add Item")
}
Button {
// Appel de la methode removeItem()
self.model.removeItem()
} label: {
Text("Remove Last")
}
}
}
}
}
struct TestView: View {
// Model recu a la creation de la vue dans ContentView
@ObservedObject var model: Model
var body: some View {
VStack {
// Iteration de chaque Post
// Si id: \.self, stuct Post doit conformer a Hashable
// Si id: \.id, struct Post doit conformer a Identifiable
// id est preferable
ForEach(model.test, id: \.id) { test in
// Recuperation et affichage du title du Post
Text(test.title)
}
}
}
}
struct ContentView_Previews: PreviewProvider {
static var previews: some View {
ContentView()
}
}