Is it possible to have a nil value in a tuple with

2019-08-08 21:33发布

问题:

I'm trying to write some code for seeding some test data into the Core Data database in an application I'm developing, about Pokémon. My code for seeding is based on this: http://www.andrewcbancroft.com/2015/02/25/using-swift-to-seed-a-core-data-database/

I am having a slight problem with one thing though. I don't seem to be able to put a nil value inside of a tuple.

I'm currently trying to seed some Pokémon Moves into the database. A move can have a bunch of different properties, but which combination it has it entirely dependent on the move itself. All seed Move data is in an array of tuples.

To demonstrate...

let moves = [
    (name: "Absorb", moveType: grass!, category: "Special", power: 20, accuracy: 100, powerpoints: 25, effect: "User recovers half the HP inflicted on opponent", speedPriority: 0),
    // Snip
]

...is fine. It's a move with all the above properties, where zero in speedPriority means something. However, some moves don't have a power or accuracy property, because they're irrelevant to that specific move. However, creating a second tuple in the array without the power or accuracy named elements, such as...

(name: "Acupressure", moveType: normal!, category: "Status", powerpoints: 30, effect: "Sharply raises a random stat", speedPriority: 0)

...understandably throws an error

Tuple types {firstTuple} and {secondTuple} have a different number of elements (8 vs. 6)

because, well, the tuples have different number of elements. So instead, I tried...

(name: "Acupressure", moveType: normal!, category: "Status", power: nil, accuracy: nil, powerpoints: 30, effect: "Sharply raises a random stat", speedPriority: 0)

but this also didn't work, as it gave the error:

Type 'Int' does not conform to protocol 'NilLiteralConvertible'

So, is there any way to do what I'm trying to do? Is there some way to either place a nil value inside the tuple, or somehow make it an optional element? With thanks!

回答1:

You could do something like below:

typealias PokemonMove = (name: String?, category: String?)

var move1 : PokemonMove = (name: nil, category: "Special")

let moves: [PokemonMove] = [
    (name: nil, category: "Special"),
    (name: "Absorb", category: "Special")
]

Add more parameters as you wish, I took just two parameters for explanation of concept.



回答2:

In the tutorial the tuples only contained two values - name and location. Since you have so many variables in one tuple you should conside putting them into a class or struct.

Using Structs or Classes also makes it easy for variables to be nil. And, since optional types have a default value of nil when setting up each move you only need to set the values that aren't nil - as shown the second example.

An example Struct is:

struct Move {
    var name: String?
    var moveType: String?
    var category: String?
    var power: Int?

    // etc etc...
}

You could then create a move:

var move = Move()
move.name = "Acupressure"
move.category = "Status"
// Don't need to set move.power to nil - it is already!

In the tutorial you need to enumerate your array of Tuples, for this to work with Structs it basically looks the same:

let moves: [Move] = // My array of moves
for move in moves {
    let newMove = NSEntityDescription.insertNewObjectForEntityForName("Move", inManagedObjectContext: context) as CoreDataMove
    newMove.name = move.name
    newMove.moveType = move.moveType
    newMove.category = move.category

    // etc etc
}


回答3:

You can achieve that using:

import Foundation

let myNil : Any? = nil

let moves = [
    (name: 1 as NSNumber, other: ""),
    (name: myNil, other: "" )
]

moves[0].name // 1
moves[1].name // nil