0

TL;博士

以下似乎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") 
            }
        }
    }
}
4

1 回答 1

1

共识是它是一个看起来像错误的功能。

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

首先不这样做的充分理由:

  • 您不应该在View初始化期间发生变异,因为那是在 body父视图的调用中

  • @StateSwiftUI 中的变量不应从您通过初始化程序传递的数据初始化;由于模型是在视图之外维护的,因此无法保证该值会真正被使用。

  • 不要尝试@Stateinit. 它只会在第一次视图创建期间工作一次(重要:不是值初始化),并且只有当视图树中的视图被重新创建/替换为相同类型但内部不同 ID 的不同视图时。

“这是一个错误”的位置(接近我的):

  • 这是由于编译器对属性包装器的实现存在人为限制。解决方法是直接通过初始化后备存储_value

解释方式和原因:

  • in 的值@State将始终使用您传入的值进行初始化init,这很简单 Swift。但是,在下一次body调用之前,SwiftUI 将调用 update 方法并重新向其中注入一个值,如果有一个先前的值将覆盖您从 init 中的值。

  • 这不是错误!:man_facepalming:它按预期/广告工作。...@State属性包装器向视图添加了一种可能的突变方式,这也意味着视图私有,而不是从父级初始化,等等。

这是飞行员错误(可能是真的):

  • 这里没有问题,除非人们误解了 State 是为了什么而建立的。
于 2020-05-13T05:12:56.257 回答