As suggested, you can use the Any type to represent the values โโof the plist dictionary. But then how do you work with data? Throw any value at any time when you are viewing it from a dictionary? This is really dirty. A better, more type-safe way of modeling plist would be to use Swift lists, also known as algebraic data types or discriminatory unions. They allow you to specify exactly which types are allowed in the dictionary and to avoid actuation. The implementation is implemented here:
// An atomic (ie 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) }
At the atomic level, only the above data types can be stored in the plist. Each "node" in a plist can ultimately be just one of these types. So, we create an enumeration that allows us to specify this.
// A value that can be stored in a plist Dictionary 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>>
Plastic is basically a dictionary of key-value pairs, and each value can be either an atomic (i.e. non-collectible) value; or it can be an array of atomic values; or it could be a dictionary of plist value pairs. The above enumeration expresses these limitations, and typalias gives the plist type an easy-to-remember name.
Given the above types, we can fully express any given plist with a safe type, for example:
// 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")]) ) ]
What it means to be safe here is that you can process any given plist with the switch and cover all the possibilities without the need for casting. You eliminate a whole class of potential runtime errors. For example:.
// See https://developer.apple.com/library/prerelease/ios/documentation/Swift/Conceptual/Swift_Programming_Language/Enumerations.html
Note that you need to wrap recursive data structures in a "field" (a pointer to the actual value) so that their sizes are finite.