SwiftUI中数据项更改时更新列表

时间:2019-11-14 00:56:03

标签: swift swiftui

我有一个采用ObservableObject协议的Activity类,并具有一个items数组属性,该属性存储也采用ObservableObject的Activity对象。

class Activity: ObservableObject, Codable, Identifiable {
    let id = UUID()
    @Published var title: String
    @Published var description: String
    @Published var numberOfTimesCompleted: Int = 0

    func encode(to encoder: Encoder) throws {
        var container = encoder.container(keyedBy: CodingKeys.self)

        try container.encode(title, forKey: .title)
        try container.encode(description, forKey: .description)
        try container.encode(numberOfTimesCompleted, forKey: .numberOfTimesCompleted)
    }

    init(title: String, description: String) {
        self.title = title
        self.description = description
        numberOfTimesCompleted = 0
    }

    required init(from decoder: Decoder) throws {
        let container = try decoder.container(keyedBy: CodingKeys.self)

        title = try container.decode(String.self, forKey: .title)
        description = try container.decode(String.self, forKey: .description)
        numberOfTimesCompleted = try container.decode(Int.self, forKey: .numberOfTimesCompleted)
    }
}

class Activities: ObservableObject {
    @Published var items: [Activity] {
        didSet {
            let encoder = JSONEncoder()
            if let encoded = try? encoder.encode(items) {
                UserDefaults.standard.set(encoded, forKey: "items")
            }
        }
    }

    init() {
        if let items = UserDefaults.standard.data(forKey: "items") {
            let decoder = JSONDecoder()
            if let decoded = try? decoder.decode([Activity].self, from: items) {
                self.items = decoded
                return
            }
        }

        self.items = []
    }
}

我正在使用List这样动态显示我的数组

List {
  ForEach(activities.items) { activity in
    NavigationLink(destination: ActivityView(activity: activity)) {
      HStack {
        Text("\(activity.numberOfTimesCompleted)")
        VStack(alignment: .leading) {
          Text(activity.title)
          Text(activity.description)
        }
      }
    }
  }
}

当我将“活动”传递到另一个视图(在NavigationLink中)并编辑numberOfTimesCompleted属性时,当我导航回到列表时,更改不会反映出来。如果将新的Activity实例添加到列表中,列表将更新,并且新的numberOfTimesCompleted值会反映在我之前编辑的Activity中。我有一种接近的感觉,但是我正在学习Swift和ObservableObject,因此缺少一些东西。

1 个答案:

答案 0 :(得分:0)

这里的问题是列表视图具有一系列活动:var items: [Activity],而子级则具有来自该阵列的单个Activity。您已经创建了活动Identifiable,并且id是常量,因此发生的事情是您从数组中传递了活动并对其进行了修改,但是就数组而言,什么都没有改变:所有对象数组中的ID完全相同,因此不会重新加载任何内容。您需要触发活动的重新加载。您可能要考虑使用一个环境对象或传递一个更改闭包,该更改闭包实际上对数组执行突变,以便重建列表视图。仅当它可以检测到已发布的数组与上一个值不同时,它才会自我重建。