SwiftUI视图(显然)在init运行之前就已经布置好了。

问题描述 投票:0回答:1

TL;DR

看来 ContentView 下文评估了该机构的 if 声明前 init 已经跑了。是有比赛条件,还是我的心理模型出了问题?

点赞

向Asperi致敬,是他提供了以下信息 状态初始化器等价物 解决了今天的问题。

编码

为什么 ContentView 显示 "dummy is nil"?似乎有什么东西被关闭了 之前 初始化器设置 dummy. 第二个赋值是怎么解决的?

class Dummy {  }

struct ContentView: View {
    @State private var dummy : Dummy?

    init() {
        print("Init") // In either case, is printed before "Body"

        // Using this assignment, "dummy is nil" shows on screen.
        self.dummy = Dummy()

        // Using this, "dummy is non-nil" shows on screen.
        // From https://stackoverflow.com/questions/61650040/swiftui-initializer-apparent-circularity
        // self._dummy = State(initialValue: Dummy())
    }

    var body: some View {
        print("Body")
        return ZStack {
            if dummy == nil {              // Decision seems to be taken
                Text("dummy is nil"    )   // before init() has finished.
            } else { 
                Text("dummy is non-nil") 
            }
        }
    }
}
initialization swiftui race-condition property-wrapper
1个回答
0
投票

一致认为,这是一个看起来像bug的功能。

有用的讨论 在Swift论坛。也在这里. 重点内容(为清晰起见进行了编辑)包括:。

很好的理由不这样做摆在首位。

  • 你不应该变异期间 View init中,因为那会在body 父视图的调用

  • @State SwiftUI中的变量不应该从你通过初始化器传递下来的数据中进行初始化;因为模型是在视图之外进行维护的,所以不能保证该值真的会被使用。

  • 不要尝试覆盖 @State的初始值,在 init. 它只会在第一次创建视图时起作用(重要的是:不是值的初始化),而且只有当视图树中的那个视图被重新创建后,才会被一个相同类型但内部ID不同的不同视图所取代。

这是一个误区 "的立场(与我的立场接近)。

  • 这是由于编译器在实现属性封装时的一个人为限制。变通的办法是直接通过初始化后盾存储。_value

解释如何和为什么。

  • 价值 @State 将始终以你传入的值进行初始化。init,这就是简单的Swift。然而在下一步之前 body 调用SwiftUI会调用update方法并重新注入一个值,如果之前有一个值,会覆盖你的init值。

  • 这不是一个错误! :man_facepalming: 它的工作原理和预期的一样。... @State 属性包装器给视图增加了一种可能的突变方式,这也是为了让视图私有化,而不是从父节点初始化,等等。

这是试点错误(可能是真的)。

  • 这里没有任何问题 除了人们误解了State是为了什么而建立的。
© www.soinside.com 2019 - 2024. All rights reserved.