programacion - swift tutorial español
¿Cómo coloco diferentes tipos en un diccionario en el lenguaje Swift? (7)
Como se ha sugerido, puede usar Any
tipo para representar los valores de un diccionario de plist. Pero entonces, ¿cómo trabajas con los datos? ¿Lanza cada valor cada vez que lo busca en el diccionario? Eso es realmente desordenado. Una forma mejor y más segura para modelar un plist sería aprovechar las enumeraciones de Swift, también conocidas como tipos de datos algebraicos o uniones discriminadas. Le permiten especificar exactamente qué tipos están permitidos en el diccionario y evitar tener que emitir. Aquí hay una implementación, explicada:
// 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)
}
En el nivel más atómico, solo los tipos de datos anteriores pueden almacenarse en un plist. Cada ''nodo'' en el plist puede, en última instancia, ser solo uno de estos tipos. Entonces creamos una enumeración que nos permite especificar esto.
// 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 es básicamente un diccionario de pares clave-valor, y cada valor puede ser un valor atómico (es decir, no de colección); o puede ser una matriz de valores atómicos; o puede ser un diccionario de pares de valores plurales. La enumeración anterior expresa estas restricciones, y las tipográficas le dan al tipo plist un nombre fácil de recordar.
Dados los tipos anteriores, podemos expresar completamente cualquier plist dado de una manera segura, por ejemplo:
// 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")])
)
]
Lo que significa ser seguro en este caso es que puede procesar cualquier plist dado usando una declaración de switch
y cubrir todas las posibilidades sin la necesidad de ningún casting. Está eliminando toda una clase de posibles errores de tiempo de ejecución. P.ej:
// 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)):
...
}
Tenga en cuenta que es necesario resumir las estructuras de datos recursivas en una ''caja'' (un puntero al valor real) para mantener sus tamaños finitos.
Swift solo permite que un diccionario contenga un solo tipo.
Esta es la definición que se toma del libro de Swift:
Un diccionario es un contenedor que almacena múltiples valores del mismo tipo
[...]
Se diferencian de las
NSDictionary
yNSMutableDictionary
de Objective-C, que pueden utilizar cualquier tipo de objeto como sus claves y valores, y no proporcionan ninguna información sobre la naturaleza de estos objetos.
Si ese es el caso, entonces, ¿cómo vamos a crear diccionarios anidados?
Imagine que tenemos un plist
que contiene elementos String, Array y Dictionary en él. Si se me permite tener solo el mismo tipo de elementos (cadena, matriz, etc.), entonces, ¿cómo voy a usar diferentes tipos de elementos almacenados en el plist?
¿Cómo coloco diferentes tipos en el mismo diccionario en Swift?
NSObject funciona para mi caso, mientras que "Any" no funciona
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
Puede lograr estructuras anidadas tipo plist utilizando Any
type para valores de diccionario, que es algo equivalente de Swift al tipo de id
Objective-C, pero también puede contener tipos de valores.
var response = Dictionary<String, Any>()
response["user"] = ["Login": "Power Ranger", "Password": "Mighty Morfin''"]
response["status"] = 200
EDITAR:
Any
parece ser mejor que AnyObject
porque en el código anterior la response["status"]
es de tipo Swift.Int
, mientras usa el tipo de valor de AnyObject
es __NSCFNumber
.
Use NSMutableDictionary de la siguiente manera:
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
Espero que esto funcione bien.
Uso: Diccionario <String, AnyObject>
var dict: Dictionary<String, AnyObject> = [
"number": 1,
"string": "Hello",
]
NSMutableDictionary to Dictionary funciona como un amuleto y le permitirá poner diferentes tipos en un Diccionario en 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)
let dictionary : Dictionary = [
"key": "value",
"key2": 2,
"key3": NSString(),
2: "test",
]
Uno puede especificar tipos que restringen el diccionario
let dictionary : Dictionary<String, String> = [
"key": "value",
"key2": 2, // This errors
]