1

I have NSDictionary with print Description as

{
    accStatus = 2;
    accessKey = "55d66e4d4f740-c24aa8ef3a28564db5a2bf77c8638478-712675299";
    email = "abc@yahoo.com";
    id = 15;
    imagePath = "";
    name = "Umar";
    notifStatus = 0;
    phone = 923217268138;
}

I am trying following code to parse

init (user: AnyObject)
{
    self.id         = (user["id"] as? Int) ?? 0

    self.accStatus  = (user["accStatus"]  as AnyObject? as? Int) ?? 0

    self.accessKey  = (user["accessKey"] as AnyObject? as? String) ?? "" // to get rid of null
    self.name       = (user["name"] as AnyObject? as? String) ?? "" // to get rid of null     
}

However its returning 0 for all ints. If i try to remove conditional ?? and replace with ! it gives me error

Could not cast value of type '__NSCFString' (0x24807ac) to 'NSNumber' (0x28d96dc).

AnyObject NSMutableDictionary clearly contains integer, how can i parse integer

jscs
  • 63,694
  • 13
  • 151
  • 195
Muhammad Umar
  • 11,391
  • 21
  • 91
  • 193
  • maybe [this answer](http://stackoverflow.com/a/24183839/2557145) will help you. [this answer](http://stackoverflow.com/a/30897914/2557145) if you are using swift 2.0 – Palle Aug 21 '15 at 01:25
  • 1
    That is not "parsing" it is just accessing values from a `NSDictionary`. – zaph Aug 21 '15 at 01:36

3 Answers3

2

You can't trust print to reveal the types of the values in the dictionary. Consider this example:

var user1: NSMutableDictionary = [
    "id1" : "1",
    "id2" : 2,
    "id3" : 3.141592654
]

for (key, value) in user1 {
    var type: String

    switch value {
    case let i as NSNumber:
        type = "NSNumber"
    case let s as NSString:
        type = "NSString"
    default:
        type = "something else"
    }

    print("\(key) is \(type)")
}

id1 is NSString
id2 is NSNumber
id3 is NSNumber

print(user1)

{
id1 = 1;
id2 = 2;
id3 = "3.141592654";
}

Note that id1 is a NSString and id2 is an NSNumber and neither has quotation marks "". id3 which is an NSNumber has quotation marks.

Because (user["id"] as? Int)! gives the error:

Could not cast value of type '__NSCFString' (0x24807ac) to 'NSNumber' (0x28d96dc)

the underlying type is NSString which will need to be converted to Int after conditionally casting them to String:

For Swift 1.2:

self.id         = (user["id"] as? String)?.toInt() ?? 0
self.accStatus  = (user["accStatus"] as? String)?.toInt() ?? 0
self.accessKey  = (user["accessKey"] as? String) ?? ""
self.name       = (user["name"] as? String) ?? ""

Note that (user["id"] as? String)?.toInt() ?? 0 uses multiple features of the Swift language to prevent a crash:

  1. If "id" is not a valid key in the user dictionary, user["key"] will return nil. Casting nil to String with as? will return nil. The optional chain ? will just return nil instead of calling toInt() and finally the nil coalescing operator ?? will turn that into 0.
  2. If user["id"] is in fact another type, then as? String will return nil and that will become 0 as above.
  3. If user["id"] is a String that doesn't convert to an Int, like "two", then toInt() will return nil which ?? will convert to 0.
  4. Finally, if user["id"] is a String that converts to an Int, then toInt() will return an Int? (optional Int) that ?? will unwrap

For Swift 2.0:

self.id         = Int(user["id"] as? String ?? "") ?? 0
self.accStatus  = Int(user["accStatus"] as? String ?? "") ?? 0

Like above Int(user["id"] as? String ?? "") ?? 0 uses multiple features of the Swift language to prevent a crash:

  1. If "id" is not a valid key in the user dictionary, user["key"] will return nil. Casting nil to String with as? will return nil. The nil coalescing operator ?? will turn that into "". Int("") will return nil which the second ?? will coalesce into 0.
  2. If user["id"] is another type, then as? String will return nil and that will become 0 as above.
  3. If user["id"] is a String that doesn't convert to an Int, then Int() will return nil which ?? will convert to 0.
  4. Finally, if user["id"] is a String that converts to an Int, then Int() will return an Int? (optional Int) that ?? will unwrap.
vacawama
  • 150,663
  • 30
  • 266
  • 294
  • my question actually was print description tells me its not a String then why its acting like a string note that values of id and accStatus are not in commas – Muhammad Umar Aug 21 '15 at 04:18
  • Updated answer. Short answer, you can't depend on print description to reveal the types. – vacawama Aug 21 '15 at 10:51
  • Please file a [bug report](http://bugreport.apple.com) WRT to this print issue, it causes a lot of confusion when debugging, I have–the more the better. – zaph Aug 21 '15 at 12:01
0

NSDictionaries can not contain integers – they contain NSNumbers. You must covert the NSNumber to an int, it is not casting.

Use:

var intValue: Int32 { get }

or

var integerValue: Int { get }
AstroCB
  • 12,337
  • 20
  • 57
  • 73
zaph
  • 111,848
  • 21
  • 189
  • 228
0

Swift 4:

self.id = user["id"].intValue

The integer value of the string, assuming a decimal representation and skipping whitespace at the beginning of the string. This property is INT_MAX or INT_MIN on overflow. This property is 0 if the string doesn’t begin with a valid decimal text representation of a number.

Reference

ricks
  • 3,154
  • 31
  • 51