【问题标题】:How do I put different types in a dictionary in the Swift Language?如何在 Swift 语言的字典中放入不同的类型?
【发布时间】:2014-07-24 04:32:33
【问题描述】:

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

以下是 Swift 书中的定义:

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

[...]

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

如果是这样,那么我们将如何创建嵌套字典?

假设我们有一个plist,其中包含字符串、数组和字典项。如果只允许我保存相同类型的项目(字符串、数组等),那么我将如何使用存储在 plist 中的不同类型的项目?

如何在 Swift 中将不同的类型放在同一个字典中?

【问题讨论】:

  • 为什么有人会下载这个问题?它有什么问题?
  • 我会想象因为标题模糊。

标签: swift dictionary


【解决方案1】:

您可以使用Any 类型的字典值实现类似plist 的嵌套结构,这在某种程度上与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 的值类型是__NSCFNumber

【讨论】:

  • 更多信息here
  • 如果类型的数量受到限制,最好使用通用协议(例如PropertyListType,使用扩展添加到类型)组合允许的类型(在这种情况下为属性列表类型)并声明字典只包含这些类型Dictionary&lt;String, PropertyListType&gt;。这种方法将有助于维护类型安全。
  • @NikolaiRuhe 你能详细说明一下吗?如何创建这样的协议?我在文档中找不到任何内容。谢谢! :)
  • @HAS 我认为@Nikolai Ruhe 的意思是Protocol as Types,您可以在Swift 书中找到更多信息:docs.swift.org/swift-book/LanguageGuide/Protocols.html
【解决方案2】:

正如建议的那样,您可以使用 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 值对的字典。上面的 enum 表达了这些约束,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 并涵盖所有可能性,而无需任何强制转换。您正在消除一整类潜在的运行时错误。例如:

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

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

【讨论】:

  • 这应该是公认的答案;它只是真正处理类型的一种。
【解决方案3】:

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

【讨论】:

  • 为了清楚起见,我建议人们使用 var d0 / d1,因为所有框架都是从零开始的。 d2 将是第三个字典。
【解决方案4】:

像这样使用 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

希望这会正常工作。

【讨论】:

    【解决方案5】:

    使用:字典

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

    【讨论】:

      【解决方案6】:

      NSMutableDictionary 到 Dictionary 的作用就像一个魅力,它允许您将不同的类型放入 Swift 语言的 Dictionary 中:

      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)
      

      【讨论】:

      • 它的作用就像一个魅力并回答了问题,那么为什么要投反对票呢?
      【解决方案7】:
      let dictionary : Dictionary = [
          "key": "value",
          "key2": 2,
          "key3": NSString(),
          2: "test",
      ]
      

      可以指定限制字典的类型

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

      【讨论】:

      • 这不起作用并抛出“无法将表达式类型'Dictionary'转换为'StringLiteralConvertible'类型”
      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2020-12-06
      • 2018-12-04
      • 2014-03-23
      • 2021-10-30
      • 2020-11-05
      • 1970-01-01
      相关资源
      最近更新 更多