如何在Swift语言中将不同类型的字典放入字典中?

时间:2014-06-03 18:01:05

标签: swift dictionary

Swift只允许字典包含单个类型。

以下是Swift书中的定义:

  

字典是一个存储多个相同类型值的容器

     

[...]

     

它们与Objective-C的NSDictionaryNSMutableDictionary类不同,后者可以使用任何类型的对象作为其键和值,并且不提供有关这些对象性质的任何信息。

如果是这种情况那么我们将如何创建嵌套字典?

想象一下,我们有一个plist,其中包含String,Array和Dictionary项。如果我只允许持有相同类型的项目(字符串,数组等),那么我将如何使用存储在plist中的不同类型的项目?

如何在Swift的同一个字典中添加不同的类型?

7 个答案:

答案 0 :(得分:92)

您可以使用Any类型为字典值实现类似plist的嵌套结构,这是Swift与Objective-C的id类型相对应但也可以保存值类型。

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

编辑:

Any似乎比AnyObject更好,因为在上面的代码中response["status"]的类型为Swift.Int,而使用AnyObject的值类型时,它是{ {1}}。

答案 1 :(得分:12)

如上所述,您可以使用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值对的字典。上面的枚举表达了这些约束,而typealias为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")])
  )
]

这里的类型安全意味着您可以使用switch语句处理任何给定的plist并覆盖所有可能性而无需任何转换。您正在消除一大类潜在的运行时错误。 E.g:

// 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)):
    ...
}

请注意,有必要将递归数据结构包装在“框”(指向实际值的指针)中,以保持其大小有限。

答案 2 :(得分:2)

NSObject适用于我的情况,而#34;任何&#34;

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

答案 3 :(得分:2)

像这样使用NSMutableDictionary:

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
希望这样可以正常工作。

答案 4 :(得分:1)

使用:字典&lt; String,AnyObject&gt;

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

答案 5 :(得分:0)

NSMutableDictionary to Dictionary就像一个魅力,可以让你在Swift语言的字典中加入不同的类型:

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)

答案 6 :(得分:-2)

let dictionary : Dictionary = [
    "key": "value",
    "key2": 2,
    "key3": NSString(),
    2: "test",
]

可以指定限制词典的类型

let dictionary : Dictionary<String, String> = [
    "key": "value",
    "key2": 2, // This errors
]