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

 大众化的公爵樱桃rwr_208 发布于 2023-01-11 19:36

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

这是Swift书中的定义:

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

[...]

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

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

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

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

2 个回答
  • 您可以使用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它的值类型__NSCFNumber.

    2023-01-11 19:38 回答
  • 如上所述,您可以使用该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 并覆盖所有可能性而无需任何转换.您正在消除一大类潜在的运行时错误.例如:

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

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

    2023-01-11 19:38 回答
撰写答案
今天,你开发时遇到什么问题呢?
立即提问
热门标签
PHP1.CN | 中国最专业的PHP中文社区 | PNG素材下载 | DevBox开发工具箱 | json解析格式化 |PHP资讯 | PHP教程 | 数据库技术 | 服务器技术 | 前端开发技术 | PHP框架 | 开发工具 | 在线工具
Copyright © 1998 - 2020 PHP1.CN. All Rights Reserved 京公网安备 11010802041100号 | 京ICP备19059560号-4 | PHP1.CN 第一PHP社区 版权所有