我有一个如此简单的选中标记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回调。但是现在我无法在View内部拥有状态,而只需要依靠外部数据源更改即可。也许这更合适,因为这样我就可以不用本地@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")
}
}
}
答案 0 :(得分:1)
isChecked
作为@State
变量 是您的真理之源。这意味着,当某些基础数据模型(例如CoreData)更改时,没关系。您的视图仅查看@State
的本地isChecked
版本。
但是看看你的看法。对我来说,它不应该拥有自己的状态。为什么?因为此视图作为复选标记视图没有语义含义。它的父级似乎拥有该状态(因此为什么会有onCheck
回调)。相反,这应该使用带有{em> 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
}
}