SwiftUI |警告:绑定首选项 _ 尝试每帧更新多次。可能的原因?

Posted

技术标签:

【中文标题】SwiftUI |警告:绑定首选项 _ 尝试每帧更新多次。可能的原因?【英文标题】:SwiftUI | Warning: Bound preference _ tried to update multiple times per frame. Possible reasons? 【发布时间】:2020-11-21 09:30:15 【问题描述】:

自从我使用首选项 (PreferenceKey,..) 以来,我在控制台中收到此消息:

Bound preference _ tried to update multiple times per frame.

经过无数次的研究,我还没有找到任何办法让它安静下来。那么...既然目前还没有针对此警告的具体问题,您认为可能的原因是什么?

如果没有,可以忽略此警告还是我必须修复它?

非常感谢!

(我试图找到一个例子,但不知何故我没有得到任何简单的警告......)

【问题讨论】:

我遇到了同样的问题。就我而言,我在 List 中使用了 anchorPreferences。 ***.com/questions/65386898/… 我正在从 GeometryReader 更新首选项值,该值嵌入​​了一个 ScrollView 跟踪滚动偏移并遇到相同的问题,Xcode 版本 13.0 beta 3。我猜,效果无害。跨度> 【参考方案1】:

onPreferenceChange 等 SwiftUI 更改处理程序在任意线程上调用。因此,如果这些更改影响您的视图,您应该重新调度以确保您在主线程上进行这些更新:

.onPreferenceChange(MyPreferenceKey.self)  newValue in
    DispatchQueue.main.async 
        widget.value = newValue
    

【讨论】:

嗯。这并没有为我解决。就我而言,我在许多不同的视图中使用相同的 PreferenceKey。这是一种有效的方法吗?具体来说,我正在确定某些视图的宽度,以便调整姐妹视图的大小。 onPreferenceChange 是订阅者 - 它不会更新首选项值。所以,这个尝试很可能行不通。 这是非常重要的,也有点令人惊讶,尽管考虑到它是有道理的。尽管如此,它应该得到更好的记录。此外,似乎在多个子视图上使用相同的首选项键会引发这种行为。不确定正确的方法是什么。 '在任意线程上调用诸如 onPreferenceChange 之类的 SwiftUI 更改处理程序'为假。在处理程序中运行“Thread.isMainThread”将给出“真”。这里发生了其他事情 嗨,友好的邻居提示:我正在努力完成与@MatthewRips 相同的任务(确定宽度)。在使用 List 而不是 ScrollView + LazyVStack 测试相同的实现之后,消息消失了(以及我也遇到的口吃问题)。因此,如果可以的话,我建议使用 List 进行测试。【参考方案2】:

我认为 Apple 工程师的这个回答描述了一般问题:

听起来您的更新有一个循环。例如,一个 GeometryReader 写入首选项,导致包含 视图调整大小,这会导致 GeometryReader 写入 再次偏好。避免产生这样的循环很重要。经常 这可以通过将 GeometryReader 在视图中移动到更高的位置来完成 层次结构,使其大小不会改变并且可以传达大小 到它的子视图而不是使用首选项。我怕我给不了 在没有看到您的代码的情况下,任何比这更具体的指导,但是 希望这可以帮助您找到问题!

https://www.bigmountainstudio.com/community/public/posts/65727-wwdc-2021-questions-answers-from-slack-the-unofficial-archive

至少它启发了我解决我案例中的相关错误并使警告消失(几乎:))。

【讨论】:

【参考方案3】:

我正在构建一个日历应用程序,基于它将选择日期设置为初始值的月份,当不使用主队列时,它会进入一个无限循环,其中包含诸如 onChange(of: String) 之类的消息的操作尝试每次更新多次框架。更改为使用主队列后解决了我的问题。

                DispatchQueue.main.async 
                    dateChosen = Date()
                

【讨论】:

以上是关于SwiftUI |警告:绑定首选项 _ 尝试每帧更新多次。可能的原因?的主要内容,如果未能解决你的问题,请参考以下文章

有没有办法使用 SwiftUI 将选项绑定到 Toggle / Slider

SwiftUI 视图首选项:overlayPreferenceValue 在复杂容器上使用时返回 nil

Groovy Shell 警告“无法打开/创建首选项根节点...”

带有 CurrentValueSubject 绑定的 TextField 上的“Binding<String> 操作尝试每帧更新多次”

SwiftUI 将数组的元素作为绑定传递给子视图

SwiftUI 在一种情况下而不是另一种情况下查看层次结构警告