#swift #struct #swiftui
#swift #структура #swiftui
Вопрос:
У меня есть простое представление SwiftUI, в котором отображаются три позиции чисел и кнопка обновления. Кнопка обновления запускает pickThree()
функцию, которая заменяет каждое число случайным.
Чтобы запустить представление, мне нужно присвоить каждой позиции начальный номер, как показано в allVals
переменной.
Я хочу начать просмотр со случайного числа в каждой позиции, а не с жестко закодированных чисел из allVals
переменной. Кажется, я должен быть в состоянии сделать это, запустив ту же pickThree()
функцию обновления… возможно, предварительно установив его в качестве значения allVals
переменной:
@State var allVals = pickThree()
Это приводит к ошибке:
Невозможно использовать элемент экземпляра ‘pickThree’ в инициализаторе свойства; инициализаторы свойства запускаются до того, как будет доступен ‘self’
Чего мне здесь не хватает?
import SwiftUI
struct ThreeCards: View {
// @State var allVals = pickThree() // PRODUCES ERROR
@State var allVals = [1,2,3]
var body: some View {
VStack {
HStack {
Text(String(allVals[0]))
Text(String(allVals[1]))
Text(String(allVals[2]))
}
Button(action: {
pickThree()
}) {
Text("Refresh")
}
}
}
func pickThree() -> [Int] {
let one = Int.random(in: 1...3)
let two = Int.random(in: 1...3)
let three = Int.random(in: 1...3)
allVals = [one, two, three]
return allVals
}
}
Комментарии:
1. вы можете инициализировать allVals как пустой [int], затем вызвать .onAppear() после закрывающей скобки одного из ваших стеков и выполнить там вызов ruction
Ответ №1:
Оператор @State var allVals = pickThree()
неявно требует self
инициализации переменной экземпляра allVals
, но когда это произойдет self
, она еще недоступна.
Существует несколько подходов.
- Вместо этого использовать статическую функцию:
Это применимо, когда вам не нужен доступ к другим переменным экземпляра.
struct ThreeCards: View {
@State var allVals = ThreeCards.pickThree()
var body: some View {
VStack {
HStack {
Text(String(allVals[0]))
Text(String(allVals[1]))
Text(String(allVals[2]))
}
Button(action: {
allVals = ThreeCards.pickThree()
}) {
Text("Refresh")
}
}
}
static func pickThree() -> [Int] {
let one = Int.random(in: 1...3)
let two = Int.random(in: 1...3)
let three = Int.random(in: 1...3)
return [one, two, three]
}
}
- Инициализировать переменную экземпляра в
init
:
struct ThreeCards: View {
@State var allVals = [Int.random(in: 1...3), Int.random(in: 1...3), Int.random(in: 1...3)]
var body: some View {
VStack {
HStack {
Text(String(allVals[0]))
Text(String(allVals[1]))
Text(String(allVals[2]))
}
Button(action: {
allVals = pickThree()
}) {
Text("Refresh")
}
}
}
init() {
allVals = pickThree()
}
func pickThree() -> [Int] {
let one = Int.random(in: 1...3)
let two = Int.random(in: 1...3)
let three = Int.random(in: 1...3)
return [one, two, three]
}
}
- Гораздо более аккуратный, для этой конкретной цели:
struct ThreeCards: View {
@State var digits = ["1", "2", "3"].shuffled()
var body: some View {
VStack {
HStack {
Text(digits[0])
Text(digits[1])
Text(digits[2])
}
Button(action: {
digits.shuffle()
}) {
Text("Refresh")
}
}
}
}
Комментарии:
1. ДА! Ваш первый метод отлично работает! Ваш второй метод (тот, который, я думаю, я должен использовать) работает нормально, но возвращает ошибку, когда я запускаю его в симуляторе » Поток 1: фатальная ошибка: индекс вне диапазона » в
Text(String(allVals[0]))
строке. Есть идеи?2. @Sam ой, извините. Для работы второго все еще нужны некоторые настройки. Я должен указать
allVals
массив целых чисел по умолчанию, чтобы избежатьindex out of range
.3. Забудьте о втором. Есть некоторое дублирование. Я придумал третий вариант для вашего конкретного контекста.
4. @BenjaminWen Третий вариант хорош и лаконичен! Все еще оборачиваю голову вокруг этого материала SwiftUI. Спасибо за ваши идеи.