Why does NSNumber confuse Bool, Int and Double, and how do you read untyped values safely?
Predict first
What does this print?
print(NSNumber(value: 1) as? Bool as Any, NSNumber(value: 2) as? Bool as Any)
- Optional(true) nil
- Optional(true) Optional(true)
- nil nil
Predict first
What does this print?
let items: [Any] = [1, 2.5]
print(items.map { $0 is Int })
- [true, false]
- [true, true]
- [false, false]
Mental model. An NSNumber is a coin with no country stamped on it. You can call it a dollar or a euro, and the cast will play along.
An NSNumber stores a number but forgets its Swift type. NSNumber(value: 1) is simultaneously an Int, a Double and a Bool as far as casts go. Cast it to Bool and 1 and 0 succeed, while 2 gives nil. So a JSON, plist or userInfo Any holding 1 may read back as true, and testing is Bool before is Int gets the wrong branch.
A native Swift Double in an Any is different: (1.0 as Any) is Int is false, because it never went through NSNumber. The robust fix is to decode into a typed model (Codable) instead of poking at Any. If you must inspect untyped values, decide the order of your checks deliberately, and treat NSNull as a separate case.
Only 0 and 1 bridge to Bool. Anything else fails the cast.
These are native Swift numbers, not NSNumbers, so their types are exact and 2.5 is not an Int.
Common traps
- Checking
is Intbeforeis Boolon parsed JSON. A realtruematches the integer branch. - Assuming
as? Boolmeans “this was a boolean”. It also accepts 1 and 0.
They might follow up with
- How does JSON
truearrive fromJSONSerialization? As anNSNumberthat also casts toInt1. - Why does
Codableavoid this? You declare each property’s type, so the decoder knows what to demand.
Related questions
- 2.5.5 When would you use JSONSerialization instead of Codable, and what does the untyped route cost?
- 2.9.1 What is toll-free bridging, and how do you convert between Swift and Foundation types?
← What is toll-free bridging, and how do you convert between Swift and… What does bridging cost, and where does it show up in a profile? →