Почему @Published обновляет текст, но не обновляет список?

Dec 15 2020

Я не понимаю, почему Textобновления, но Listнет.

У меня есть модель с @Publishedмассивом дат. Также есть способ генерировать текст из дат.

Вот упрощенная версия:

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

}

И я показываю этот текст с моей точки зрения. Вот упрощенная версия:

struct DataView: View {

    @ObservedObject var model: DataModel

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

}

Это работает: когда пользователь из пользовательского интерфейса в представлении добавляет дату model.selectedDates, текст сводки правильно обновляется.


Теперь я хочу заменить текст списком строк.

Меняю способ:

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

И изменим вид:

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

Но это не работает: в списке вообще нет текста, он никогда не обновляется, когда пользователь добавляет дату в model.selectedDates.

Что я делаю неправильно?

Ответы

2 Nate Dec 15 2020 at 08:34

Мне удалось найти этот ответ на предыдущий пост на SO, который может быть решением вашей проблемы. Когда вы говорите, что в списке вообще нет текста, вы выполняли отладку, чтобы убедиться в этом, или на экране просто не отображались данные?

Когда я сделал копию вашего фрагмента кода и возился с ним, оказалось, что в списке действительно были данные, которые List пытался отобразить на экране, но фрейм List перекрывался Scrollview. Вложение всего в GeometryReader и указание размера кадра в List дало программе функциональность, которая звучит так, как будто вы ищете.

1 nicksarno Dec 15 2020 at 10:22

Либо используйте ScrollView, либо список для ваших данных. Если список имеет несколько значений, он автоматически превращается в список с возможностью прокрутки. Итак, я считаю, что вы можете полностью удалить ScrollView.

1 Asperi Dec 15 2020 at 10:53

Вот фиксированный рабочий вариант (с некоторыми репликациями - так что вам нужно адаптировать его обратно к вашему проекту).

Протестировано с 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)
                }
            }
        }
    }
    
}