user1547019
user1547019

Reputation: 39

"Type of expression is ambiguous without more context" error in multi-dimensional array

I am trying to create an array that would preferably store the object in this format [[[String, CGPoint, Bool]]], but I get errors all over the place so I decided to set it as [[[AnyObject]]].

Here is my code for declaring the array:

var savePlayerState:[[[AnyObject]]] = []

As you can see it's a multidimensional array, which I need to store 3 things: the current time, the player's location, and a simple Bool. Here is how I am trying to save the data to the array:

savePlayerState.append([timeLabel.text, player.position, isPlayerAlive])

My error is this:

Type of expression is ambiguous without more context

I really am not sure what's going on, I have tried casting several different ways but I am stuck. I also do need to save all of these variables in an array, which I will be appending to every game loop and saving in a log for testing. How can I accomplish this? I feel like the solution is simple, I'm just missing it.

Upvotes: 2

Views: 913

Answers (2)

vacawama
vacawama

Reputation: 154711

Usually using AnyObject in Swift is the wrong approach unless it is required for interfacing to Cocoa/Cocoa touch. You should probably use a custom structure to store PlayerState and then create an array of those:

struct PlayerState {
    var time: String
    var position: CGPoint
    var isAlive: Bool
}

var savePlayerState:[PlayerState] = []

savePlayerState.append(PlayerState(time: "10:05", position: CGPointMake(2.3, 2.4), isAlive: true))
savePlayerState.append(PlayerState(time: timeLabel.text, position: player.position, isAlive: isPlayerAlive))

You can implement the CustomStringConvertible protocol for your structure to make printing your log easier:

struct PlayerState: CustomStringConvertible {
    var time: String
    var position: CGPoint
    var isAlive: Bool
    var description: String { return "time: \(time), position: (\(position.x), \(position.y)), isAlive: \(isAlive)" }
}

savePlayerState.append(PlayerState(time: "10:05", position: CGPointMake(2.3, 2.4), isAlive: true))
savePlayerState.append(PlayerState(time: "11:03", position: CGPointMake(1.0, 1.0), isAlive: false))

for state in savePlayerState {
    print(state)
}

Output:

time: 10:05, position: (2.3, 2.4), isAlive: true
time: 11:03, position: (1.0, 1.0), isAlive: false

Upvotes: 2

R Menke
R Menke

Reputation: 8411

I don't think you actually want/need a multi-dimensional array. If you do absolutely need it to be a nested collection, please explain why. The code below illustrates how your array works. (I made it an array of Int for simplicity)

var savePlayerState:[[[Int]]] = [[[1],[2]],[[3],[4]]] // this a triple nested array
var firstNest = savePlayerState.first // [[1], [2]]
var secondNest = firstNest!.first // [1]
var thirdNest = secondNest!.first // 1

You can't append an Int to savePlayerState because it expects an element of type [[Int]]. One dimension less than itself.

In your code :

savePlayerState.append([timeLabel.text, player.position, isPlayerAlive])

You are appending a 1 dimensional array to a 3 dimensional array. Which does not work because it expects a 2 dimensional array. You are also not appending one object with three values, but three different values with different types.

Retrieving one specific value will be a nightmare.

This will work :

savePlayerState.append([[("someText", CGPointZero, true)]])

But it will still not be very useful.

Notice the () around the values. This will make the values into a tuple. Then you already at least have one element for each collection of values.


What you do want is an element that holds the three values. This can be a custom struct or class, but it can also be a tuple.

When working with tuples it is convenient to create a typealias

// this is a typealias to give the tuple a name
typealias aStringAPointandABool = (string:String,point:CGPoint,bool:Bool)

var tupleArray : [aStringAPointandABool] = []
var myTyple = (string:"SomeString",point:CGPointZero,bool:true)
tupleArray.append(myTyple)

// this is a struct with variables for the different values
struct myContainer {
    var string : String = ""
    var point : CGPoint = CGPointZero
    var bool : Bool = true
}

var myStructArray : [myContainer] = []
var myStruct = myContainer(string: "SomeString", point: CGPointZero, bool: true)
myStructArray.append(myStruct)

Upvotes: 2

Related Questions