Pourquoi @Published met à jour le texte mais ne met pas à jour la liste?

Dec 15 2020

Je ne comprends pas pourquoi les Textmises à jour mais le Listne le fait pas.

J'ai un modèle avec un @Publishedqui est un tableau de dates. Il existe également une méthode pour générer du texte à partir des dates.

Voici une version simplifiée:

class DataModel: NSObject, ObservableObject {
    
    @Published var selectedDates: [Date] = []

    func summary() -> String {
        var lines: [String] = []
        for date in selectedDates.sorted().reversed() {
            let l = "\(someOtherStuff) \(date.dateFormatted)"
            lines.append(l)
        }
        return lines.joined(separator: "\n")
    }

}

Et je montre ce texte à mon avis. Voici une version simplifiée:

struct DataView: View {

    @ObservedObject var model: DataModel

    var body: some View {
        ScrollView {
            Text(model.summary())
        }
    }

}

Cela fonctionne: lorsque l'utilisateur, à partir de l'interface utilisateur de la vue, ajoute une date à model.selectedDates, le texte de résumé est correctement mis à jour.


Maintenant, je veux remplacer le texte par une liste de lignes.

Je change de méthode:

    func summary() -> [String] {
        var lines: [String] = []
        for date in selectedDates.sorted().reversed() {
            let l = "\(someOtherStuff) \(date.dateFormatted)"
            lines.append(l)
        }
        return lines
    }

Et changez la vue:

    var body: some View {
        ScrollView {
            List {
                ForEach(model.summary(), id: \.self) { line in
                    Text(line)
                }
            }
        }
    }

Mais cela ne fonctionne pas: il n'y a pas du tout de texte dans la liste, il n'est jamais mis à jour lorsque l'utilisateur ajoute une date à model.selectedDates.

Qu'est-ce que je fais mal?

Réponses

2 Nate Dec 15 2020 at 08:34

J'ai pu trouver cette réponse à un article précédent sur SO qui peut être la solution à votre problème. Lorsque vous dites qu'il n'y avait aucun texte dans la liste, avez-vous débogué pour vérifier cela, ou n'y avait-il simplement aucune donnée affichée à l'écran?

Lorsque j'ai fait une copie de votre extrait de code et que je l'ai manipulé, il est apparu qu'il y avait en fait des données dans la liste que la liste tentait d'afficher à l'écran, mais le cadre de la liste était remplacé par le Scrollview. L'imbrication de tout à l'intérieur d'un GeometryReader et l'attribution d'une taille d'image à la liste ont donné au programme la fonctionnalité qu'il semble que vous recherchez.

1 nicksarno Dec 15 2020 at 10:22

Utilisez un ScrollView ou une liste pour vos données. Si une liste a plusieurs valeurs, elle se transforme automatiquement en une liste déroulante. Donc, je pense que vous pouvez simplement supprimer entièrement ScrollView.

1 Asperi Dec 15 2020 at 10:53

Voici une variante de travail fixe (avec quelques réplications - vous devez donc l'adapter à votre projet).

Testé avec Xcode 12.1 / iOS 14.1

class DataModel: NSObject, ObservableObject {
    
    @Published var selectedDates: [Date] = []
    
    func summary() -> [String] {
        var lines: [String] = []
        for date in selectedDates.sorted().reversed() {
            let l = "someOtherStuff \(date)"
            lines.append(l)
        }
        return lines
    }
    
}

struct DataView: View {
    
    @ObservedObject var model: DateDataModel = DataModel()
    
    var body: some View {
        VStack {
            Button("Add") { model.selectedDates.append(Date())}
            List {
                ForEach(model.summary(), id: \.self) { line in
                    Text(line)
                }
            }
        }
    }
    
}