正如建议的那样,您可以使用 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)):
...
}
请注意,有必要将递归数据结构包装在一个“盒子”(指向实际值的指针)中以保持它们的大小有限。