Swift只允许一个字典包含一种类型。
以下是取自 Swift 书中的定义:
字典是存储同一类型的多个值的容器
[...]
它们不同于Objecte-C的NSDic的
和NSMutableDic的
类,这些类可以使用任何类型的对象作为它们的键和值,并且不提供有关这些对象性质的任何信息。
如果是这样的话,那么我们将如何创建嵌套词典?
假设我们有一个保存字符串、数组和字典项的<code>plist</code>。如果只允许我保存相同类型的项(字符串、数组等),那么我如何使用plist中存储的不同类型的项?
如何在 Swift 中将不同的类型放在同一个字典中?
你可以使用 Any
类型作为字典值来实现类似 plist 的嵌套结构,这是 Swift 与 Objective-C 的 id
类型相对应,但也可以保存值类型。
var response = Dictionary<String, Any>()
response["user"] = ["Login": "Power Ranger", "Password": "Mighty Morfin'"]
response["status"] = 200
编辑:
< code>Any似乎比< code>AnyObject更好,因为在上面的code 响应["status"]
属于< code>Swift类型。Int,当使用< code>AnyObject的值类型时,它是< code>__NSCFNumber。
正如所建议的,您可以使用< code>Any类型来表示plist字典的值。但是你如何处理这些数据呢?每当你从字典中查找一个值的时候,就转换它。那真的很乱。一种更好、更安全的plist建模方法是利用Swift的枚举,也称为代数数据类型或区分联合。它们让您准确地指定字典中允许的类型,并避免强制转换。下面是一个实现,解释如下:
// 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)
}
在最原子的级别上,只有上述数据类型可以存储在plist中。plist中的每个“节点”最终只能是这些类型之一。所以我们创建一个枚举,让我们指定它。
// 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>>
plist基本上是键值对的字典,每个值可以是原子(即非集合)值;或者它可以是原子值的数组;或者它可以是字符串plist值对的字典。上面的枚举表达了这些约束,类型别名为plist类型提供了一个易于记忆的名称。
给定上述类型,我们可以以类型安全的方式完全表达任何给定的 plist,例如:
// 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")])
)
]
在这里,类型安全的含义是,您可以使用< code>switch语句处理任何给定的plist,并涵盖所有可能性,而无需任何强制转换。您消除了一整类潜在的运行时错误。例如:
// 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)):
...
}
请注意,有必要将递归数据结构包装在“框”(指向实际值的指针)中,以保持其大小有限。
NSObject适用于我的情况,而“Any”不适用
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