You need to initialize the array to a given size before updating items at positions within it. It might help to start with the single-dimensional case:
var labels: [SKLabelNode] = [] // creates an empty array
// since the array is empty, this will generate an index out of range error:
labels[0] = SKLabelNode(fontNamed: "Font")
Instead you need to extend the array with the elements you want to add. For example,
for _ in 0..<labelsInLevel {
labels.append(SKLabelNode(fontNamed: "Font"))
}
(the _ means “I don’t care about the actual number of each iteration - normally if you wanted to know this was the ith time around the loop you’d write for i in 0..<n)
There are nicer ways to do this though. But be careful with one of them, the initializer for Array that takes a count and a repeatedValue:
let labels = Array(count: labelsInLevel, repeatedValue: SKLabelNode(fontNamed: "Font”))
SKLabelNode is a reference type. That means that a variable only refers to an instance, and assigning one variable to another only copies the reference. So for example:
let variableOne = SKLabelNode(fontNamed: "Foo")
let variableTwo = variableOne
// variableTwo now refers to the same instance of SKLabelNode
variableTwo.fontName = "Bar"
print(variableOne)
// fontName will now be “Bar” even though this was
// done via variableTwo
You get the same effect with the repeatedValue code above. The label is created once, and the same reference to it is inserted multiple times. Change a property on one label in the array, and you change them all. Note the for loop version does not have this problem. Every time around the loop, a new SKLabelNode instance will be created. They won’t be shared.
An alternative to the repeatedValue initializer, that creates without using a for loop is to use map:
(0..<labelsInLevel).map { _ in SKLabelNode(fontNamed: "Font") }
Here, just like in the for loop version, a new SKLabelNode instance is created every time.
(again, we use the _ to indicate we don’t care about the number of the iteration)
Finally, to create the nested multidimensional arrays with the loops inside, you can run map multiple times:
var scoreLabels =
(0..<modesInGame).map { _ in
(0..<levelsInMode).map { _ in
(0..<labelsInLevel).map { _ in
SKLabelNode(fontNamed: "Font")
}
}
}