SwiftUI 中子结构的计算属性未更新

Posted

技术标签:

【中文标题】SwiftUI 中子结构的计算属性未更新【英文标题】:Computed Property from Child Struct Not Updating in SwiftUI 【发布时间】:2021-10-16 04:45:38 【问题描述】:

我的 SwiftUI 应用中有一个数据模型,看起来像这样:

struct Entry: Identifiable
  var id = UUID().uuidString
  var name = ""

  var duration: Int
    //An SQLite query that returns the total of the "duration" column
    let total = try! dbc.scalar(tableFlight.filter(db.entry == id).select(db.duration.total))
    return Int(total)
  


struct Flight: Identifiable
  var id = UUID().uuidString
  var duration = 0
  var entry: String?

我有一个ObservableObject 视图模型,它生成如下条目:

class EntryModel: ObservableObject
  static let shared = EntryModel()
  @Published var entries = [Entry]()

  init()
    get()
  

  func get()
    //Stuff to fetch the entries
    entries = //SQLite query that returns an array of Entry objects
  

最后,在我的View 中,我列出了所有条目名称及其关联的duration,如下所示:

ForEach(modelEntry.entries) entry in
  VStack
    Text(entry.name) //<-- Updates fine
    Text(entry.duration) //<-- Gets set initially, but no updates
  

我遇到的问题是,当我为 Entry 更新 Flight 时,我认为 duration 不会更新。我知道这不会发生,因为只有 entries 会在更改时重绘。

但即使我在EntryModel 中手动调用get() 函数,关联的duration 仍然不会更新。

有没有更好的方法来做到这一点?如何让父元素的计算属性在其子元素更新时重新计算?

【问题讨论】:

get() 之后调用objectWillChange.send() 怎么样?我不确定这是否可行,但值得一试——至少它会向 View 发出尝试更新的信号。 我不明白的是,您的持续时间甚至不是来自您的入门模型中的任何内容。那么你到底在你的入门模型中更新了什么?因为 dbc 不在您的模型中。我只能假设(并且担心)它是某种全局变量(或者你使用小写的类来混淆读者)。 duration属性下的注释所示,这是一个返回相关数据的SQLite查询。 dbc 是一个数据库单例。不过,这与手头的问题并不真正相关。 抱歉,这只是反值类型编码。值类型不应该有这样的隐藏依赖关系,特别是如果在不同的时间点使用,它的行为会有所不同。那最好是一个全局函数,或者更好的是,它是暴露dbc 依赖项的类的一部分。 我明白了。不要那样做。它会伤害你。将该查询放入初始化程序中。每次重新渲染视图时都会运行您的查询,不仅仅是为了描述,而是为了任何目的。 【参考方案1】:

我想通了。我的实际代码在ForEach 中使用了一个孩子View,其中VStack 是。我只是将entry 传递给它,所以这些值只是最初设置的,因此没有反应。

通过将 entry 更改为 Binding,它正在工作:

ForEach($modelEntry.entries) $entry in
  ChildView(entry: $entry)

请注意,$modelEntry 上的 $ 和返回 $entryXcode 13+ 功能(但向后兼容 ios 14 和 macOS 11.0)。

【讨论】:

以上是关于SwiftUI 中子结构的计算属性未更新的主要内容,如果未能解决你的问题,请参考以下文章

SwiftUI 计算属性显示“在视图更新期间修改状态,这将导致未定义的行为。”错误

SwiftUI 中的计算(NSObject)属性不会更新视图

SwiftUI 基于计算属性显示警报

已发布的属性未在 SwiftUI 中更新

SwiftUI - @State 属性未更新

计算属性未在道具更改时更新