web-dev-qa-db-fra.com

Comment puis-je mettre différents types dans un dictionnaire dans la Swift Language?

Swift permet uniquement à un dictionnaire de contenir un seul type.

Voici la définition tirée du livre Swift book:

Un dictionnaire est un conteneur qui stocke plusieurs valeurs du même type

[...]

Elles diffèrent des classes NSDictionary et NSMutableDictionary d'Objective-C, qui peuvent utiliser n'importe quel type d'objet comme clé et valeur et ne fournissent aucune information sur la nature de ces objets.

Si tel est le cas, comment allons-nous créer des dictionnaires imbriqués?

Imaginons que nous ayons un plist contenant des éléments String, Array et Dictionary. Si je suis autorisé à ne conserver que le même type d’éléments (chaîne, tableau, etc.), comment puis-je utiliser différents types d’éléments stockés dans la liste d’expériences?

Comment puis-je mettre différents types dans le même dictionnaire dans Swift?

50
lionserdar

Vous pouvez obtenir des structures imbriquées ressemblant à des listes de plis en utilisant Any type pour les valeurs de dictionnaire. Swift est un peu l'équivalent du type id d'Objective-C, mais peut également contenir des types de valeur.

var response = Dictionary<String, Any>()
response["user"] = ["Login": "Power Ranger", "Password": "Mighty Morfin'"]
response["status"] = 200

MODIFIER:

Any semble être meilleur que AnyObject car dans le code ci-dessus, response["status"] est de type Swift.Int, en utilisant le type de valeur AnyObject, il s’agit de __NSCFNumber.

92
MDJ

Comme cela a été suggéré, vous pouvez utiliser le type Any pour représenter les valeurs d'un dictionnaire de listes d'adresses. Mais alors, comment travaillez-vous avec les données? Jetez chaque valeur chaque fois que vous le cherchez dans le dictionnaire? C'est vraiment désordonné. Un moyen plus efficace de modéliser un plist serait de tirer parti des énumérations de Swift, également appelées types de données algébriques ou syndicats discriminés. Ils vous permettent de spécifier exactement quels types sont autorisés dans le dictionnaire et d’éviter de devoir lancer des castes. Voici une implémentation, a expliqué:

// An atomic (i.e. non-collection) data type in a plist.
enum PListNode {
  case PLN_String(String)
  case PLN_Integer(Int)
  case PLN_Float(Double)
  case PLN_Bool(Bool)
  case PLN_Date(CFDate)
  case PLN_Data(CFData)
}

Au niveau le plus atomique, seuls les types de données ci-dessus peuvent être stockés dans un plist. Chaque "nœud" dans la liste de sélection ne peut finalement être que n de ces types. Nous créons donc une énumération qui nous permet de spécifier cela.

// A value that can be stored in a plist Dictionary's key-value pair.
enum PListValue {
  case PLV_Node(PListNode)
  case PLV_Array(PListNode[])
  case PLV_Dictionary(Dictionary<String, Box<PListValue>>)
}

typealias PList = Dictionary<String, Box<PListValue>>

Un plist est essentiellement un dictionnaire de paires clé-valeur, et chaque valeur peut être une valeur atomique (c'est-à-dire non collectée); ou ce peut être un tableau de valeurs atomiques; ou il peut s'agir d'un dictionnaire de paires valeur-chaîne. L'énumération ci-dessus exprime ces contraintes et les typealias donnent au type plist un nom facile à retenir.

Étant donné les types ci-dessus, nous pouvons exprimer complètement un plist donné de manière sécurisée, e.g .:

// Example translated from
// https://developer.Apple.com/library/Mac/documentation/Darwin/Reference/ManPages/man5/plist.5.html
let myPlist: PList = [
  "Year Of Birth": Box(PLV_Node(PLN_Integer(1965)))
, "Pets Names":    Box(PLV_Array([]))
, "Picture":       Box(PLV_Node(PLN_Data(...)))
, "City of Birth": Box(PLV_Node(PLN_String("Springfield")))
, "Name":          Box(PLV_Node(PLN_String("John Doe")))
, "Kids Names":    Box(
    PLV_Array([PLN_String("John"), PLN_String("Kyra")])
  )
]

Cela signifie que vous pouvez utiliser n'importe quel type de plist avec une instruction switch et couvrir toutes les possibilités sans qu'il soit nécessaire d'utiliser un transtypage. Vous éliminez toute une classe d'erreurs d'exécution potentielles. Par exemple.:

// See https://developer.Apple.com/library/prerelease/ios/documentation/Swift/Conceptual/Swift_Programming_Language/Enumerations.html#//Apple_ref/doc/uid/TP40014097-CH12-XID_189 for explanation
switch myPlist["Year Of Birth"] {
  case Box(.PLV_Node(let plvNodeValue)):
    ...
  case Box(.PLV_Array(let plvArrayValue)):
    ...
  case Box(.PLV_Dictionary(let plvDictionaryValue)):
    ...
}

Notez qu'il est nécessaire d'encapsuler les structures de données récursives dans une "boîte" (un pointeur sur la valeur réelle) pour que leurs tailles soient finies.

13
Yawar

Utilisez NSMutableDictionary comme ceci:

var dictInfo : NSMutableDictionary = [ "lang_key": "1"]
    dictInfo["food_type"]     =   lbl_TypeOfFood.text
    dictInfo["search_text"]   =   txt_Search.text
    dictInfo["date"]          =   lbl_Date.text
    dictInfo["opening_hours"] =   lbl_OpeningHours.text

espérons que cela fonctionnera bien.

2
Alok

NSObject fonctionne pour mon cas alors que "Tout" ne fonctionne pas

var d:Dictionary<String,NSObject> = [:]
d["key1"] = "ddd"
d["key2"] = 111  //OK
NSLog("%@", d) //OK

var d2:Dictionary = Dictionary<String,Any>()
d2["key1"] = "ddd"
d2["key2"] = 111
NSLog("%@", d2) //I got error here
2
Soyoes

Utilisation: Dictionnaire <String, AnyObject>

var dict: Dictionary<String, AnyObject> = [
    "number": 1,
    "string": "Hello",
]
1
iamamused

NSMutableDictionary to Dictionary fonctionne comme un charme et vous permettra de mettre différents types dans un dictionnaire dans le Swift Language:

let nsMutableDictionary = NSMutableDictionary()
nsMutableDictionary[NSFontAttributeName] = UIFont(name: "HelveticaNeue", size: 12.0)!
nsMutableDictionary[NSForegroundColorAttributeName] = UIColor.redColor()

let dictionary: Dictionary<NSObject, AnyObject> = nsMutableDictionary

self.attributedPlaceholder = NSAttributedString(string: textParam, attributes: dictionary)
0
King-Wizard