在init()构造函数中初始化的@State的SwiftUI视图

在init()构造函数中初始化的@State的SwiftUI视图,swift,swiftui,swiftui-state,Swift,Swiftui,Swiftui State,我有这样一个简单的复选标记SwiftUI视图。 它显示在列表中,可以通过点击来切换,也可以在从数据源(例如核心数据)刷新时进行切换 我的第一个实现是 struct RoundedCheckmark: View { @State var isChecked : Bool let onCheck: (Bool) -> Void func toggle() { isChecked = !isChecked; onCheck(isChecked) } init

我有这样一个简单的复选标记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闭包/回调保存了更改,并刷新了ok

但在外部刷新(如推送通知)之后,刷新此视图的核心数据中的底层模型不会正确更改@State属性

在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")

        }

    }
}

isChecked
,因为
@State
变量是真理的源泉。这意味着,当一些底层数据模型(如CoreData)发生变化时,这并不重要。您的视图仅查看已检查的
的本地
@状态
版本

但是看看你的观点。对我来说,它不应该拥有自己的状态。为什么?因为此视图作为复选标记视图没有语义意义。它的父级似乎拥有该状态(因此存在
onCheck
回调)。相反,应该使用不带回调的
@Binding

struct rounded复选标记:视图{
@已检查绑定变量:Bool
var body:一些观点{
按钮(操作:{isChecked.toggle()}){
图像(已选中?“选中选中选中标记”:“未选中选中选中标记”)
}
}
现在,您的父母拥有该州,您可以推断其语义含义:

struct CheckmarkOwner:视图{
@状态变量showFavoritesOnly=false
var body:一些观点{
//内容
圆形复选标记(选中:$showFavoritesOnly)
//现在,当切换“showFavoritesOnly”时,会通知其他内容
如果只表现得好的话{
//可切换内容
}
//更多内容
}
}

看起来您已经回答了自己的问题……是的,但我不明白为什么第一个解决方案不起作用。这是因为每个视图实例都创建了新的@State,但视图使用的是旧的@State?如果是,那么我如何更改此状态(以及我是否应该尝试更改它?)你是说这就是为什么我会有两个真实来源吗?我已经测试过它,在其他地方它也可以工作,即如果我将一些外部日期传递给init(),然后使用它们初始化@State,并使用State(initialValue:)。然后如果数据在外部来源中刷新,那么init()将再次调用,State(initialValue:)重新初始化,通常正常工作。也有这样的情况,当此外部数据是核心数据管理对象时,必须知道此对象类似于便笺簿,有时我们可以更改它,并认为刷新后它没有正确更新,但它的状态没有使用ManagedObjectContext.rollBack回滚