Por que @Published atualiza o texto, mas não atualiza a lista?

Dec 15 2020

Não entendo por que as Textatualizações, mas Listnão.

Tenho um modelo com @Publisheduma matriz de datas. Também existe um método para gerar texto a partir das datas.

Esta é uma versão simplificada:

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

}

E eu mostro esse texto no meu ponto de vista. Esta é uma versão simplificada:

struct DataView: View {

    @ObservedObject var model: DataModel

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

}

Funciona: quando o usuário, da IU na Visualização, adiciona uma data model.selectedDates, o texto do resumo é atualizado corretamente.


Agora quero substituir o texto por uma lista de linhas.

Eu mudo o método:

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

E mude a visão:

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

Mas isso não funciona: não há nenhum texto na lista, ela nunca é atualizada quando o usuário adiciona uma data a model.selectedDates.

O que estou fazendo de errado?

Respostas

2 Nate Dec 15 2020 at 08:34

Consegui encontrar essa resposta em um post anterior no SO que pode ser a solução para o seu problema. Quando você disse que não havia nenhum texto na lista, você depurou para verificar isso ou simplesmente não havia dados sendo mostrados na tela?

Quando fiz uma cópia do seu trecho de código e mexi nele, parecia que realmente havia dados na lista que a Lista estava tentando exibir na tela, mas o quadro da Lista estava sendo substituído pela Visualização de rolagem. Aninhar tudo dentro de um GeometryReader e dar um tamanho de quadro à Lista deu ao programa a funcionalidade que parece que você está procurando.

1 nicksarno Dec 15 2020 at 10:22

Use um ScrollView ou uma Lista para seus dados. Se uma lista tiver vários valores, ela se tornará automaticamente uma lista rolável. Então, acredito que você pode simplesmente remover o ScrollView inteiramente.

1 Asperi Dec 15 2020 at 10:53

Aqui está uma variante corrigida (com algumas réplicas - então você precisa adaptá-la de volta ao seu projeto).

Testado com 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)
                }
            }
        }
    }
    
}