【问题标题】:Using @State resolves into 'self' used before all stored properties are initialized使用 @State 解析为在所有存储属性初始化之前使用的“自我”
【发布时间】:2020-11-23 20:21:43
【问题描述】:

我在使用 @State 属性时遇到了问题。

我的 ContentView.swift 看起来像这样:

import SwiftUI

struct ContentView: View {
    @State var showText: Bool = true
    
    var Mod: Modifier
    init() {
        Mod = Modifier(showText: $showText) // Throws error -> 'self' used before all stored properties are initialized ('self.Mod' not initialized)
    }
    
    var body: some View {
        VStack {
            if showText == true {
                Text("Hello, World!")
            }
            Mod
        }
    }
}

struct ContentView_Previews: PreviewProvider {
    static var previews: some View {
        ContentView()
    }
}

而我的 Modifier.swift 中调用 Modifier 视图的代码如下:

import SwiftUI

struct Modifier: View {
    @Binding var showText: Bool
    
    var body: some View {
        VStack {
            Button("Hide Text") {
                self.showText.toggle()
            }
        }
    }
}

我从我的实际项目中创建了这个简化的代码,我的问题更容易理解。

问题

问题是init函数中的代码导致错误,我不知道如何解决。

我尝试了什么以及我需要什么

因为这只是我的实际代码的简化版本,所以我需要对我的代码有一些要求:

  • Mod 不能是计算变量
  • 不知何故,我需要 Modifier 视图作为我的 ContentView 中名为 Mod 的变量
  • 当我删除@State 属性和@Binding 属性和$ 时,代码工作并产生0 个错误。但我需要使用 @State 属性(不幸的是,这会导致我的代码出错)
  • 隐藏和显示文本的按钮也应该可以工作

如果有人能给我提示,我将非常感激。非常感谢您的帮助!

【问题讨论】:

    标签: ios swift swiftui


    【解决方案1】:

    我确实找到了一种方法来做到这一点。我不确定它是否合适,但这里有详细信息。

    问题在于 SwiftUI 似乎不允许在 body 之外设置绑定。所以这个解决方案返回了一个新的 Modifier 实例

    struct Modifier: View {
        @Binding var showText: Bool
        
        var body: some View {
            VStack {
                Button("Hide Text") {
                    self.showText.toggle()
                }
            }
        }
        
        // this function returns a new instance with the binding
        func bind(to binding: Binding<Bool>) -> Self {
            return Modifier(showText: binding)
        }
    }
    

    还有ContentView的代码,我们可以在body中调用这个函数:

    struct ContentView: View {
        @State var showText: Bool = true
        var Mod: Modifier
        
        init() {
            Mod = Modifier(showText: .constant(true)) // .constant() gives a placeholder Binding
        }
        
        var body: some View {
            return VStack {
                if showText == true {
                    Text("Hello, World!")
                }
                Mod.bind(to: $showText)
            }
        }
    }
    

    经过测试,文本可以隐藏/显示。希望这能有所帮助。

    【讨论】:

    • 非常感谢!对此,我真的非常感激。这为我解决了这个问题并且有效。 ?
    • @sp4c38 很高兴我能提供帮助! ^-^
    【解决方案2】:
    Mod = Modifier(showText: _showText.projectedValue)
    

    如果您愿意,可以将其设为 let 而不是 var

    【讨论】:

    • 感谢您的回答。当我尝试这个时,它会编译并运行。但是当我点击按钮时,文本不再消失。你有什么方法可以让我使用@State 并且文本消失吗?
    • 否;你的例子实际上不起作用。我认为这只是一个简化。使用 Xcode 12 获得更好的反馈。 stackoverflow.com/questions/62633728/…
    • 感谢您调查我的问题!我将尝试使用 Xcode 12 以获得更好的反馈。如果我能找到答案,我会在这里发布答案。再次感谢您的帮助。
    【解决方案3】:

    body 上下文中使用视图

    struct ContentView: View {
        @State var showText: Bool = true
        
        var body: some View {
            VStack {
                if showText == true {
                    Text("Hello, World!")
                }
                Modifier(showText: $showText)
            }
        }
    }
    

    【讨论】:

    • 可以的。但我需要 Mod 变量。在我的简化版本中它可以工作,但在我的实际项目中,我需要多次使用相同的视图,并希望将其存储在一个变量中以供使用。
    • @sp4c38 将视图存储为变量几乎总是错误的方法(在大多数正常情况下),因此您的设计可能走错了轨道
    • 嗯好的。谢谢。在我的实际项目中,当从第一个视图中点击按钮时,我需要将视图(我想存储在变量中)解析为另一个视图以调用函数。所以我可能应该为此使用不同的方法?
    • @sp4c38 我并不完全清楚你所说的“需要解析视图......”是什么意思。视图应该被认为是声明性的 UI 结构,你应该根据数据(状态变量、视图模型)进行推理并操作它们。阅读@Binding@State@ObservedObject/ObservableObject,并阅读在视图树层次结构上下“视图”消息的各种方式。这是一个很好的explanation
    • 我尝试了几种不同的方法,其中许多告诉我“访问状态的值不在安装在视图上。这将导致初始值的恒定绑定并且不会更新。 "我相信,如果不从body 开始,就不可能以这种方式分配绑定
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2016-04-01
    • 2020-02-04
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2018-09-09
    • 1970-01-01
    相关资源
    最近更新 更多