【问题标题】:Conditions inside init() in SwiftUISwiftUI 中 init() 中的条件
【发布时间】:2020-10-20 08:26:01
【问题描述】:

我需要在 SwiftUI 中使用 init,但我只是在学习初始化程序。我找到了很多复杂的例子,但我无法理解基础知识。

如何根据其他 var 的值(例如基于切换的真/假)在 init() 中初始化不同的值?

示例代码

我正在尝试这样的事情:

import SwiftUI

struct ToggleView: View {
    
    @State var toggleValue: Bool = true
    
    var testValue: String
    
    init() {
        if toggleValue {
            self.testValue = "true"
        } else {
            self.testValue = "false"
        }
    }
    
    var body: some View {
        
        VStack {
            Toggle(isOn: $toggleValue) {
                Text("True or false?")
            }.padding()
            
            Text("Selected value:")
            Text("\(testValue)")
        }
    }
}

struct ToggleView_Previews: PreviewProvider {
    static var previews: some View {
        ToggleView()
    }
}

但与 if toggleValue { 一致,我收到一个错误:

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

我尝试过改变:

var testValue: String

init() {

到:

@Binding var testValue: String

init(testValue: Binding<String>) {

但它也不起作用。如何将此 testValue 与切换绑定,因此在点击切换后,我的应用会打印:“Selected value: false”?

【问题讨论】:

  • 您根本不需要testValue。只需使用Text("\(toggleValue)") 而不是Text("\(testValue)")。事实上,您不应该将第二个东西绑定到切换,因为 SwiftUI 喜欢单一的事实来源。
  • 谢谢。但我需要在这个(或另一个简单的例子)上了解 init 。在我正在开发的一个应用程序中,我在使用 fetchrequest 和动态过滤器时遇到了 init 问题。如果不理解与布尔值相关的 inits,我就无法前进。以及下一步中的可选布尔值

标签: swift swiftui toggle init


【解决方案1】:

TLDR;你永远不能用另一个存储属性初始化一个存储属性。如果您想用相同的值初始化两个属性,则该值必须来自初始化程序中的参数或某个常量。


编译器实际上给出了一个非常有用的错误。在使用self 之前,需要初始化所有存储的属性。在您的示例中,您有两个存储属性:toggleValuetestValuetoggleValue 已初始化,但 testValue 未初始化。由于读取存储属性是using self 的一个示例,您不能使用存储属性来初始化另一个存储属性。您可以使用init() 中的参数初始化属性。

例如:

init(initialValue: Bool) {
    testValue = initialValue ? "true" : "false"
}

或者您可以使 testValue 成为依赖于另一个属性的计算属性:

var testValue: String {
    toggleValue ? "true" : "false"
}

如果您想保持testValuetoggleValue 同步并且能够修改 testValue,您可以使用绑定:

var testValue: Binding<String> { 
    Binding<String>(
        get: { toggleValue ? "true" : "false" },
        set: { toggleValue = $0 == "true" }
    )
}

如果你只想用 toggleValue 初始化 testValue 同步,你可以使用静态常量:

static let initialValue = true
@State var toggleValue = ToggleView.initialValue
var testValue = ToggleView.initialValue ? "true" : "false"

或者在初始化器中使用一个常量:

init() {
    let initialValue = true
    toggleValue = initialValue
    testValue = initialValue ? "true" : "false"
    // Note that in this case the compiler will inform you the 'false'
    // branch will never be executed (which is correct). To prevent this
    // you can either depend on a static constant, create your own
    // extension on bool to provide a string, or just use:
    // testValue = "\(initialValue)"
}

请注意,结构有一个隐式初始化器,它存储的属性按出现顺序列出。将初始化属性作为可选参数。这意味着您可以通过以下方式初始化 ToggleView(无需指定初始化程序):

ToggleView(toggleValue: false, testValue: true)
ToggleView(testValue: true)

【讨论】:

  • 在最后一个示例中,您的意思是我可以将属性从一个视图初始化到另一个视图?例如,在 ContentView 中有ToggleView(testValue: true)?这个我知道。但是我仍然无法仅在这个视图中进行初始化。我试过init(initialValue: Bool) { testValue = initialValue } 因为我猜testValue 应该是字符串。但是当我将它更改为 String 时,我得到了另一个错误。我应该写 initialValue 还是它是一些实际价值的占位符?我都试过了,还是不行。我认为问题在于我对 inits 的理解有限:/
  • 作为第一个问题的答案是的。我错过了 testValue 是一个字符串,我会更新答案。别担心,我们都是从某个地方开始的。
  • initialValue 是参数的名称。你可以使用任何你喜欢的名字。在init()范围内有效。
  • 感谢您帮助我。我现在在 SceneDelegate 中遇到错误:Missing argument for parameter 'initialValue' in call。我用我的代码做了什么 - 我已经注释掉了我的 init() {...} 并添加了你的 init。我理解那里的代码:如果 initialValue 为真,testValue 将为“真”。但我不知道为什么它不起作用以及在我的示例中它如何与切换连接?如果可行,更改 Toggle 将如何更改 testValue 中的文本,因为它们没有连接到任何地方?
  • 如果您在 ToggleView 的 init 中有一个参数,则必须在构造它时提供该参数(例如在您的 SceneDelegate 中)。切换视图(初始值:真)。如果您不希望这样,请选择其他选项之一。
猜你喜欢
  • 2022-07-11
  • 1970-01-01
  • 2019-12-19
  • 2021-08-30
  • 2021-06-05
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多