Aldwych is a JSON parsing repo I've written for Swift, which is hosted on GitHub.
The problem
NSJSONSerialization can write Bool values but it imports them as NSNumber values of zero or one, representing false and true respectively. The problem is further exacerbated by the fact that all NSNumbers can be cast to Bool and all Bool values can be cast to NSNumber. This makes it very difficult to distinguish between them.The solution
An NSNumber created from a Bool does retain enough knowledge about itself, however, to know that it is equal in value and type to an NSNumber instantiated with a Bool of the same kind. This is thanks to its inheritance from NSValue. So while the following will return true,NSNumber(bool: true).isEqualToNumber(NSNumber(integer: 1)) // trueif we instead use the NSValue method isEqualToValue(),
NSNumber(bool: true).isEqualToValue(NSNumber(integer: 1)) // falsefalse will be returned. This enables the following code to be written:
else if let v = v as? NSNumber { // test to see if a bool if handleBool && v.isEqualToValue(NSNumber(bool: true)) || handleBool && v.isEqualToValue(NSNumber(bool: false)) { if boolDict == nil { boolDict = DictionaryAnd this is all we need to distinguish between a Bool and a number. The rest of the code follows the same pattern as every other type that Aldwych handles.() } if boolDict != nil { boolDict![k] = Bool(v) } } else { if numDict == nil { numDict = Dictionary () } if numDict != nil { numDict![k] = v } } }
Conclusion
Not only does this knowledge help in distinguishing Bool from a number but it helps us distinguish Doubles from Integers, for example:
NSNumber(double: 1).isEqualToNumber(NSNumber(integer: 1)) // true NSNumber(double: 1).isEqualToValue(NSNumber(integer: 1)) // falseAnd this is super useful to know when working with the NSNumbers that are generated by NSJSONSerialization and in turn Aldwych.
Update
The true/false test has been working perfectly, but I posted a question to StackOverflow just to check there wasn't a different way of testing for Bool. And as a result I've updated Aldwych with a simpler and stronger approach through an NSNumber extension:
extension NSNumber { func isBoolNumber() -> Bool { let boolID = CFBooleanGetTypeID() // the type ID of CFBoolean let numID = CFGetTypeID(self) // the type ID of num return numID == boolID } }which enables me to replace this line of code
if handleBool && v.isEqualToValue(NSNumber(bool: true)) || handleBool && v.isEqualToValue(NSNumber(bool: false))with this
if handleBool && v.isBoolNumber()
Rather than explain the logic here, I recommend you read it directly on SO.
Comments
Post a Comment