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
etNSMutableDictionary
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?
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
.
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.
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.
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
Utilisation: Dictionnaire <String, AnyObject>
var dict: Dictionary<String, AnyObject> = [
"number": 1,
"string": "Hello",
]
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)