SwiftUI在使用之前初始化数组

huangapple go评论51阅读模式
英文:

SwiftUI initialize array before use

问题

我有一个空的结构体数组。在尝试显示它之前,我想要初始化它。我可能做了一些愚蠢的事情。在我的视图中,我放了一个初始化。我运行了调试器,并在附加时停在了append这里。在调试区域中,它显示我有0个值。这并没有改变,后来当我尝试显示数据时,我得到了索引超出范围的致命错误。我知道在创建数组时,第0个元素是超出范围的,但我仍然希望在运行之前它会被初始化,显然是徒劳的希望。

另一件事。我可能做错了,也不反对改变我的代码。我想要的是在启动应用程序时创建一个包含6个元素的数组。构成数组的结构体不需要初始化程序。

该数组是一个状态变量,因为我将要更改其中元素的值,当我更改它们时,我希望进行重绘。我不会更改元素的数量,只会更改现有元素的数据。

编辑:我似乎记得我可以将一些东西放在应用程序文件中,这将对所有人都可用。我不会把我的数据移到那里没有问题,但在使用它的视图中拥有它似乎更简单。

另一个编辑:我更改了数组的定义以创建元素,它显然起作用了。这很好,但仍然令我感到困惑的是为什么初始化没有起作用。可能会再次遇到这个问题。

struct Player {
  var name = ""
}
struct ContentView: View {
  @State private var players: [Player] = []
  init (){
    for _ in 0...5 {
      players.append(Player())
    }
  }
  
  var body: some View {
    HStack {
      TextField ("Player 1", text: $players[0].name)
    }
  }
}
英文:

I have an empty array of structures. I want to initialize it before I try to display it. I probably did something stupid. In my view I put an init. I ran the debugger and stopped at the append. Down in the debug area it said I had 0 values. That did not change and later when I went to display the data I got the fatal error that the index was out of range. I know when I created the array the 0 element was out of range, but I went through the init code in the, apparently fruitless, hope it would get initialized before it ran.

On another note. I am probably doing it wrong and would not be adverse to changing my code. What I want is an array with 6 elements created when I start the application. The structure that makes up the array does not require an initializer.

The array is a State variable because I am going to change the values for elements in it and when I change them I want a redraw. I am not going to change the number of elements, just data in the existing elements.

Edit: I seem to remember that I can put stuff in the app file that will be available to all. I would not have a problem moving my data there, but it seemed simpler to have it in the view that used it.

Another edit: I changed the definition of the array to create the elements and it apparently worked. That's fine, but it still puzzles me why init did not work. Probably going to run across the iagain.

struct Player {
  var name = ""
}
struct ContentView: View {
  @State private var players: [Player] = []
  init (){
    for _ in 0...5 {
      players.append(Player())
    }
  }
  
  var body: some View {
    HStack {
      TextField ("Player 1", text: $players[0].name)
    }
  }
}

答案1

得分: 1

永远不要在 SwiftUI 视图的主体中对空数组使用索引下标,因为任何init方法都会在首次渲染视图之后调用。

安全的 Swifty 初始化数组的替代方法是 init(repeating:count:) API。

struct ContentView: View {
  @State private var players = Array(repeating: Player(), count: 6)
  
  var body: some View {
  ...
英文:

Never use index subscripting in the body of a SwiftUI view on an empty array because any init method is called after the view in rendered the first time.

A safe swifty alternative to initialize the array is the init(repeating:count:) API

struct ContentView: View {
  @State private var players = Array(repeating: Player(), count: 6)
  
  var body: some View {
  ...

答案2

得分: 0

Init仍然有效,但它的行为不如预期,因为在SwiftUI中,View的body属性会被立即评估。因此,尝试从空数组中访问元素将导致'索引超出范围'错误。 <br>
为了解决这个问题,可以根据您的代码进行轻微修改:

直接初始化:

@State private var players: [Player] = {
    var array = [Player]()
    for _ in 0...5 {
        array.append(Player())
    }
    return array
}()

或者:

@State private var players = Array(repeating: Player(), count: 6)

间接初始化:

@State private var players: [Player]

init() {
    var array = [Player]()
    for _ in 0...5 {
        array.append(Player())
    }
    _players = State(wrappedValue: array)
}

@State private var players: [Player]

init() {
    _players = State(initialValue: Array(repeating: Player(), count: 6))
}
英文:

Init still works, but it doesn't behave as expected because in SwiftUI, the body property of a View is evaluated immediately. Therefore, attempting to access an element from an empty array will result in an 'Index out of range' error. <br>
To address this issue based on your code, you can make a slight modification as follows:

Direct initialization:

@State private var players: [Player] = {
    var array = [Player]()
    for _ in 0...5 {
        array.append(Player())
    }
    return array
}()

or:

@State private var players = Array(repeating: Player(), count: 6)

Indirect initialization:

@State private var players: [Player]

init() {
    var array = [Player]()
    for _ in 0...5 {
        array.append(Player())
    }
    _players = State(wrappedValue: array)
}

or

@State private var players: [Player]

init() {
    _players = State(initialValue: Array(repeating: Player(), count: 6))
}

答案3

得分: 0

错误似乎在于我无法在init中更新@State变量。我在原始帖子中指出,调试器中的条目计数在我添加条目时没有变化。我移除了@State,并将TextField更改为Text,它就像一台冠军一样工作。我进行了另一个测试,其中我创建了包含条目的数组,并在init中尝试更改其中一个。代码运行时没有错误,但更改没有显示出来。我移除了@State,它运行正常。

我在Stack Overflow 上找到了这个问题。

英文:

The error appears to be that I can not update @State variables in the init. I pointed out in the original post that the count of entries, in the debugger, did not change as I added the entries. I removed the @State, and changed TextField to Text, and it worked like a champ. I had another test where I created the array with entries and in the init I tried to change one of them. The code ran with no errors, but the change did not show up. I removed the @State and it ran fine.

I found this on stack overflow

huangapple
  • 本文由 发表于 2023年7月7日 05:50:00
  • 转载请务必保留本文链接:https://go.coder-hub.com/76632710.html
匿名

发表评论

匿名网友

:?: :razz: :sad: :evil: :!: :smile: :oops: :grin: :eek: :shock: :???: :cool: :lol: :mad: :twisted: :roll: :wink: :idea: :arrow: :neutral: :cry: :mrgreen:

确定