SwiftUI:'self' 在所有存储的属性初始化之前使用

SwiftUI: 'self' used before all stored properties are initialized

是的,我知道以前有人问过这个问题,但接受的答案对我不起作用。这些答案确实修复了编译器错误,但是当我从我的 ContentView.init 方法中将 'self' 传递给 class 的初始化程序时,并且 class 稍后调用了一个方法ContentView,'self' 不是正确的实例。回调 setVpnState 设置 @State 变量的值,这会导致 UI 更新。但事实并非如此,并且在 lldb 中进行检查时,它显然不相同 'self'(ContentView 的实例)。

这是我最初尝试做的事情:

struct ContentView: View {
    
    let iwinsController: IWiNSController

    init() {
        iwinsController = IWiNSController(view: self)
    }

    var body: some View {
        .
        .
        .
    }
        
    func setVpnState(_ state: ButtonState) {
        self.buttonAttributes = buttonConfig[state]!
    }
}

如您所料,我得到的错误是 'self' used before all stored properties are initialized

然后我尝试了这个问题的两个答案:

这确实满足了编译器的要求,但正如我所说,当从我的控制器对象调用 setVpnState 时,'self' 是不正确的。

所以,我必须做的是在不通过 'self' 的情况下初始化我的控制器,然后在 onAppear 中明确设置视图。这行得通。但这意味着在我的控制器中我每次使用它时都必须打开 view

感觉不是很'Swifty'。我是 Swift 的新手,想以公认的方式进行此操作。

struct ContentView: View {

    let iwinsController: IWiNSController

    init() {
       self.iwinsController = IWiNSController()
    }

    var body: some View {
        .
        .
        .
        }.onAppear {
            iwinsController.setView(view: self)
        }
    }
    
    func setVpnState(_ state: ButtonState) {
        self.buttonAttributes = buttonConfig[state]!
    }
}

如果我正确理解了这个问题,听起来您希望视图从您的视图中跟踪一些 vpnState class,并且您正试图将引用从视图传递到控制器对象,但这与 SwiftUI 的设计方式相反。

从根本上说,您应该将视图视为由框架在幕后更新的只读对象。您将它们锁定在 属性 或对象上以进行观察,并且当该事物发生变化时,视图会自动更新为新值。

@State 变量旨在严格在您的视图中使用,例如完全在视图中用于动画或其他一些中间状态。在这种情况下,Swifty 要做的事情是使用 @ObservedObject@EnvironmentObject 为您观察对象的状态。

至于为什么 self 在您使用它时是一个“不同的”对象,那是因为 struct 是值类型而不是引用类型。每次更改时,它都会被 Swift 销毁并重新创建。在对象上的值发生更改的意义上,它不是“更新”的。