Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Assign a [String:AnyObject] to [String:AnyObject] in Swift replaces comma with semi-colon

Tags:

ios

swift

I have

var params = [String:AnyObject]()

I have a function which returns an [String:AnyObject]. So, I want to assign that to a key of params like this:

params["phoneDetails"] = getPhoneDetails()

The problem I am facing is, the return of getPhoneDetails() is different from the value in params["phoneDetails"].

Here is the output of getPhoneDetails()

[locale: en, ostype: 32bit, appversion: 4.0.0, architecture: x86, version: 8.1]

Here is the output of params["phoneDetails"]:

Optional({
    appversion = "4.0.0";
    architecture = "x86 ";
    locale = en;
    ostype = 32bit;
    version = "8.1";
})

So, instead of a comma, I see a semi-colon, when using println(params["phoneDetails"]).

I want it to be same as the return type of getPhoneDetails. What am I doing wrong?

like image 647
Rishi Avatar asked Feb 08 '15 14:02

Rishi


1 Answers

The reason for this is that Swift is implicitly converting your Swift.Dictionary into an NSDictionary:

let d: [String:AnyObject] = ["one":"1","two":"2"]
// Swift.Dictionary implements Printable.description 
// (which println uses) as [key:value, key:value]
d.description

let nsd = d as NSDictionary
// NSDictionary on the other hand, implements
// it as {\n    key = value;\n   key = value;\n}
nsd.description

The reason for this conversion is your use of AnyObject. In theory, AnyObject can only store reference types (i.e. classes). Try the following in a playground without any import statements at the top i.e. remove import UIKit or whatever:

// this won’t even compile - Strings aren’t classes, they’re structs
// so you can’t assign them to AnyObject
let d: [String:AnyObject] = ["one":"1","two":"2"]

// this fixes that:
let e: [String:String] = ["one":"1","two":"2"]
// but this won’t compile:
let o: AnyObject = e  // [String:String] doesn’t conform to protocol AnyObject

But import Foundation and suddenly magic happens. Two bits of magic in fact: string literals can now create NSString objects, which are classes and so do conform to AnyObject. And Swift dictionaries can be silently converted to NSDictionary objects, which also are classes so conform to AnyObject. That latter one is what’s happening to you, and so you get a different output, because your type is indeed of a different type.

If you don’t want them to be of different types, you have two choices – return an NSDictionary from your getPhoneDetails function (ick) or stop using AnyObject and instead declare your dictionary to be of type [String:[String:String]] (yay, but leading to stronger types and value rather than reference semantics, which may mean having to refactor other code).

(or I guess you could switch to [String:Any] but there lies madness)

like image 92
Airspeed Velocity Avatar answered Nov 15 '22 06:11

Airspeed Velocity