Этот файл предназначен для основной структуры приложения. Вот откуда возникает ошибка: «Отсутствует аргумент для параметра numberOfDoors в вызове». Это потому, что он хочет, чтобы я добавил

ContentView(numberOfDoors: <#Int#>) 

Но у меня возникли проблемы с выяснением, как я могу получить то, что пользователь выбирает как 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("\($0) doors")
                    }
                }
                
                ForEach(multiOptions.indices, id: \.self) { index in
                    TextField("Enter your option...", text: $multiOptions[index])
                        .padding()
                        .textFieldStyle(RoundedBorderTextFieldStyle())
                }
            }
            
            Section {
                Text("\(numberOfDoors + 1)")
            }
        }
    }
}
}
0
Calvin Wood 10 Окт 2021 в 10:46

2 ответа

Лучший ответ

Одна из наиболее важных частей программирования 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.

0
Paulw11 10 Окт 2021 в 09:48

На мой взгляд, в вашем коде есть две проблемы.

  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("\($0) 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, вам сначала нужно инициализировать View.

Переменная @State заключена в оболочку свойств, где исходной переменной при инициализации является _variable. Следовательно, вам нужно инициализировать переменную @State следующим образом:

_myVariable = State(wrappedValue: myContent)

Если вы этого не сделаете, вы получите ошибку, как вы упомянули.

С уважением, McUserT

0
MacUserT 10 Окт 2021 в 11:27