缺少参数但需要根据用户输入更改参数

Missing parameter but need parameter to be changed based on user input

此文件用于应用程序的主要结构。这就是错误的来源,即“调用中缺少参数 'numberOfDoors' 的参数”。这是因为它要我添加

ContentView(numberOfDoors: <#Int#>) 

但我无法找到如何获得用户选择的整数而不是我静态地在其中输入数字。

import SwiftUI

@main
struct NumOfDoorsApp: App {
    var body: some Scene {
        WindowGroup {
            ContentView()
        }
    }
 }

这是我的项目文件。

import SwiftUI

struct ContentView: View {

@State var numberOfDoors: Int
@State var multiOptions: Array<String>

init(numberOfDoors: Int) {
    self.numberOfDoors = numberOfDoors
    self.multiOptions = [String](repeating: "", count: numberOfDoors)
}

var body: some View {
    NavigationView {
        Form{
            Section {
                Picker("Number of doors", selection: $numberOfDoors) {
                    ForEach(1 ..< 64) {
                        Text("\([=12=]) doors")
                    }
                }
                
                ForEach(multiOptions.indices, id: \.self) { index in
                    TextField("Enter your option...", text: $multiOptions[index])
                        .padding()
                        .textFieldStyle(RoundedBorderTextFieldStyle())
                }
            }
            
            Section {
                Text("\(numberOfDoors + 1)")
            }
        }
    }
}
}

我认为您的代码有两个问题。

  1. 不要使用参数初始化 ContentView。特别是,因为您希望从 0 扇门的值开始并让用户选择多少扇门。
  2. 您不能像这样直接初始化 @State 值:self.numberOfDoors = numberOfDoors.

我建议使用以下代码,它对我有用。

import SwiftUI

struct ContentView: View {
    
    @State private var numberOfDoors: Int
    @State private var multiOptions: Array<String>

    init() {
        _numberOfDoors = State(wrappedValue: 0)
        _multiOptions = State(wrappedValue: [String](repeating: "", count: 1))
    }

    var body: some View {
        NavigationView {
            Form{
                Section {
                    Picker("Number of doors", selection: $numberOfDoors) {
                        ForEach(1 ..< 64) {
                            Text("\([=10=]) doors")
                        }
                    }
                    
                    ForEach(multiOptions.indices, id: \.self) { index in
                        TextField("Enter your option...", text: $multiOptions[index])
                            .padding()
                            .textFieldStyle(RoundedBorderTextFieldStyle())
                    }
                }
                
                Section {
                    Text("\(numberOfDoors + 1)")
                }
            }
        }
    }
}

问题是,当您初始化 ContentView 时,@State 或 @StateObject 变量尚不存在。您首先需要初始化视图,然后才能分配@State 变量。

@State 变量被包装在属性 包装器中,其中初始化时的原始变量是_variable。因此,您需要像这样初始化一个@State 变量:

_myVariable = State(wrappedValue: myContent)

如果你不这样做,就会出现你提到的错误。

亲切的问候, McUserT

SwiftUI 编程最重要的部分之一是为您的视图创建合适的模型。

@State 属性适用于本地的、通常是独立的属性,但对于您的主要数据模型或需要用户操作模型的地方,它们通常不是一个好的解决方案。

在您的情况下,您希望数组的大小根据选定的门数而改变,因此您需要某个地方来存放该程序代码;模型就是那个地方。

这是一个您可以使用的简单模型对象

class DoorModel: ObservableObject {
    
    @Published var numberOfDoors: Int {
        didSet {
            self.adjustArray(newSize: numberOfDoors)
        }
    }
    @Published var doors:[String]
    
    init(numberOfDoors: Int) {
        self.numberOfDoors = numberOfDoors
        self.doors = [String](repeating: "", count: numberOfDoors)
    }
    
    private func adjustArray(newSize: Int) {
        let delta = newSize - doors.count
        
        print("new size = \(newSize) Delta = \(delta)")
        
        if delta > 0 {
            doors.append(contentsOf:[String](repeating: "", count: delta))
        } else if delta < 0 {
            doors.removeLast(-delta)
        }
    }
}

请注意,您仍然需要通过初始化程序为您的模型提供门的起始数量。每当该值发生变化时,didSet 属性 观察者都会调用一个函数在数组末尾添加或删除元素。

您可以在带有 @StateObject 装饰器的视图中使用此模型。这确保在重绘视图时创建并重用单个实例

struct ContentView: View {
    
    @StateObject var model = DoorModel(numberOfDoors: 1)
    
    var body: some View {
        NavigationView {
            Form{
                Section {
                    Picker("Number of doors", selection: $model.numberOfDoors) {
                        ForEach(1 ..< 64) { index in
                            Text("\(index) doors").tag(index)
                        }
                    }
                    
                    ForEach($model.doors.indices, id: \.self) { index in
                        TextField("Enter your option...", text: $model.doors[index])
                            .padding()
                            .textFieldStyle(RoundedBorderTextFieldStyle())
                    }
                }
            }
        }
    }
}

我添加了 .tag 修饰符以确保选择器能够正确处理基于 1 的列表;默认情况下,标签将基于 0。