在 init() 构造函数中初始化的带有 @State 的 SwiftUI 视图
Posted
技术标签:
【中文标题】在 init() 构造函数中初始化的带有 @State 的 SwiftUI 视图【英文标题】:SwiftUI View with @State that is initialized in init() constructor 【发布时间】:2020-02-26 10:50:48 【问题描述】:我有这样一个简单的复选标记 SwiftUI 视图。 它显示在列表中,可以通过点击它来切换,或者可以在从数据源(例如核心数据)刷新时切换
我的第一个实现是
struct RoundedCheckmark: View
@State var isChecked : Bool
let onCheck: (Bool) -> Void
func toggle() isChecked = !isChecked; onCheck(isChecked)
init(isChecked: Bool, onCheck: @escaping (Bool) -> Void = _ in )
self._isChecked = State(initialValue: isChecked)
self.onCheck = onCheck
var body: some View
Button(action: toggle)
Image(isChecked ? "CheckedCheckmark" : "UncheckedCheckmark")
它似乎工作我可以切换它并正确加载。在切换时,我通过 onCheck 关闭/回调保存了更改,并且刷新正常。
但是在外部刷新(如推送通知刷新底层模型)之后,此视图的核心数据刷新不会正确更改 @State 属性 isChecked。
在 init() 中,我得到了 isChecked 的新值,并使用 State(initialValue: ) 重新初始化了 @State。但是在正文中,我从旧的 @State 属性中获取了 isChecked 的旧值。所以视图确实有错误的图像。
这是一种解决方法,即仅依赖 let isChecked 属性和 onCheck 回调。但是现在我的视图中不能有状态,我只能依赖外部数据源的变化。也许它更合适,因为这样我有一个没有本地 @State 存储的单一事实来源。
struct RoundedCheckmark: View
let isChecked: Bool
let onCheck: (Bool) -> Void
func toggle() onCheck(isChecked)
init(isChecked: Bool, onCheck: @escaping (Bool) -> Void = _ in )
self.isChecked = isChecked
self.onCheck = onCheck
var body: some View
Button(action: toggle)
Image(isChecked ? "CheckedCheckmark" : "UncheckedCheckmark")
【问题讨论】:
看起来您回答了自己的问题... 是的,但我不明白为什么第一个解决方案不起作用。是因为 View 的每个实例都创建了新的@State,但 View 使用的是旧的?如果是这样,那么我如何改变这种状态(以及我是否应该尝试改变它?)你的意思是为什么我会有两个真相来源? 【参考方案1】:isChecked
作为@State
变量是你的真实来源。这意味着当某些底层数据模型(如 CoreData)发生变化时,这无关紧要。您的视图仅查看isChecked
的本地@State
版本。
但是看看你的观点。对我来说,它不应该拥有自己的状态。为什么?因为这个视图作为复选标记视图没有语义意义。它的父级似乎拥有该状态(因此有一个onCheck
回调)。相反,这应该使用带有 no 回调的@Binding
:
struct RoundedCheckmark: View
@Binding var isChecked: Bool
var body: some View
Button(action: isChecked.toggle() )
Image(isChecked ? "CheckedCheckmark" : "UncheckedCheckmark")
现在你的父母拥有这个状态,你可以推断它的语义:
struct CheckmarkOwner: View
@State var showFavoritesOnly = false
var body: some View
// content
RoundedCheckmark(isChecked: $showFavoritesOnly)
// and now something else will get notified when `showFavoritesOnly` gets toggled
if showFavoritesOnly
// toggleable content
// more content
【讨论】:
我已经对其进行了测试,并且在其他地方它可以工作,即如果我将一些外部日期传递给 init() 而不是使用它们来初始化 @State 和 State(initialValue: )。然后,如果该数据在外部源中刷新,则再次调用 init(),并重新初始化 State(initialValue:),它通常可以正常工作。也有这种外部数据是 Core Data 托管对象的情况,那么重要的是要知道这个对象就像暂存器,有时我们可以更改它并认为刷新后它没有正确更新但它的状态没有滚动返回使用 ManagedObjectContext.rollBack以上是关于在 init() 构造函数中初始化的带有 @State 的 SwiftUI 视图的主要内容,如果未能解决你的问题,请参考以下文章
Kotlin类的初始化 ③ ( init 初始化块 | 初始化顺序 : 主构造函数属性赋值 -> 类属性赋值 -> init 初始化块代码 -> 次构造函数代码 )