How to put different words in a Swift dictionary?

Swift only allows a dictionary to contain one type.

Here is the definition taken from Swift's book:

A dictionary is a container that stores multiple values โ€‹โ€‹of the same type

[...]

They differ from the Objective-C s NSDictionary and NSMutableDictionary , which can use any type of object as their keys and values โ€‹โ€‹and do not provide any information about the nature of these objects.

If so, how will we create nested dictionaries?

Suppose we have a plist that contains the String, Array, and Dictionary elements. If Im is allowed to hold only the same type of elements (string, array, etc.), then how will I use different types of elements stored in plist?

How to put different types in the same dictionary in Swift?

+48
dictionary swift
Jun 03 '14 at 18:01
source share
7 answers

You can achieve nested structures in the form of a plist, using the Any type for dictionary values, which is Swift somewhat similar to the Objective-C id , but can also contain value types.

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

EDIT:

Any seems better than AnyObject , because in the above code, response["status"] is of type Swift.Int , when using the value type of AnyObject it is __NSCFNumber .

+83
Jun 03 '14 at 18:11
source share

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

Note that you need to wrap recursive data structures in a "field" (a pointer to the actual value) so that their sizes are finite.

+9
Jun 05 '14 at 3:17
source share

Usage: Dictionary <String, AnyObject>

 var dict: Dictionary<String, AnyObject> = [ "number": 1, "string": "Hello", ] 
+2
Jun 05
source share

NSObject works for my case, and "Any" doesn't

 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 
+2
Jun 05 '14 at 6:42
source share

Use NSMutableDictionary as follows:

 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 

hope this works fine.

+1
Jun 18 '15 at 13:35
source share

NSMutableDictionary to Dictionary works like a charm and allows you to put various types into a 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) 
0
Nov 20 '14 at 1:21
source share
 let dictionary : Dictionary = [ "key": "value", "key2": 2, "key3": NSString(), 2: "test", ] 

You can specify types that restrict the dictionary.

 let dictionary : Dictionary<String, String> = [ "key": "value", "key2": 2, // This errors ] 
-2
Jun 03 '14 at 18:09
source share



All Articles