How to know the type of number stored on NSNumber?
Use CFNumberGetType
CFNumberGetType((CFNumberRef)number);
You can throw this value into a switch statement for each value of the enum CFNumberType
.
Is there a correct way to determine that an NSNumber is derived from a Bool using Swift?
You can ask the same question for Objective-C, and here is an answer in Objective-C - which you can call from, or translate into, Swift.
NSNumber
is toll-free bridged to CFNumberRef
, which is another way of saying an NSNumber
object is in fact a CFNumber
one (and vice-versa). Now CFNumberRef
has a specific type for booleans, CFBooleanRef
, and this is used when creating a boolean CFNumberRef
aka NSNumber *
... So all you need to do is check whether your NSNumber *
is an instance of CFBooleanRef
:
- (BOOL) isBoolNumber:(NSNumber *)num
{
CFTypeID boolID = CFBooleanGetTypeID(); // the type ID of CFBoolean
CFTypeID numID = CFGetTypeID((__bridge CFTypeRef)(num)); // the type ID of num
return numID == boolID;
}
Note: You may notice that NSNumber
/CFNumber
objects created from booleans are actually pre-defined constant objects; one for YES
, one for NO
. You may be tempted to rely on this for identification. However, though is currently appears to be true, and is shown in Apple's source code, to our knowledge it is not documented so should not be relied upon.
HTH
Addendum
Swift code translation (by GoodbyeStackOverflow):
func isBoolNumber(num:NSNumber) -> Bool
{
let boolID = CFBooleanGetTypeID() // the type ID of CFBoolean
let numID = CFGetTypeID(num) // the type ID of num
return numID == boolID
}
How can I distinguish a boolean NsNumber from a real number?
The objCType
method gives information about the type of the data contained in the
number object:
NSNumber *n = @(1.3);
NSLog(@"%s", [n objCType]); // "d" for double
NSNumber *b = @YES;
NSLog(@"%s", [b objCType]); // "c" for char
The possible values are documented in
"Type Encodings"
in the "Objective-C Runtime Programming Guide".
Since BOOL
is defined as unsigned char
, it is reported as such by this method.
This means that you cannot distinguish it from a NSNumber
object containing any char
.
But it is sufficient to check between "boolean" and "numeric":
if (strcmp([obj objCType], @encode(BOOL)) == 0) {
// ...
} else if (strcmp([obj objCType], @encode(double)) == 0) {
// ...
} else {
// ...
}
Swift check if NSNumber is Double
You can get type of the number stored using low-level CoreFoundation
API:
extension NSNumber {
var type: CFNumberType {
return CFNumberGetType(self as CFNumber)
}
}
And then you can use it.
Your plus
function gonna be something like that:
extension NSNumber {
func plus(other: NSNumber) -> NSNumber {
switch type {
case .sInt8Type, .charType:
return NSNumber(value: self.int8Value + other.int8Value)
case .sInt16Type, .shortType:
return NSNumber(value: self.int16Value + other.int16Value)
case .sInt32Type, .longType:
return NSNumber(value: self.int32Value + other.int32Value)
case .sInt64Type, .longLongType:
return NSNumber(value: self.int64Value + other.int64Value)
case .float32Type, .floatType:
return NSNumber(value: self.floatValue + other.floatValue)
case .float64Type, .doubleType:
return NSNumber(value: self.doubleValue + other.doubleValue)
case .intType, .cfIndexType, .nsIntegerType:
return NSNumber(value: self.intValue + other.intValue)
case .cgFloatType:
switch MemoryLayout<CGFloat>.size {
case 4:
return NSNumber(value: self.floatValue + other.floatValue)
default:
return NSNumber(value: self.doubleValue + other.doubleValue)
}
}
}
}
Determine that `true` is a Bool and not a number equal to 1
1
, 1.0
, true
, all types are bridged to NSNumber
You can check the objCType
let some : AnyObject = true
if let type = String.fromCString(some.objCType) {
switch type {
case "c" : print("is Bool", some as! Bool)
case "q" : print("is Int", some as! Int)
case "d" : print("is Double", some as! Double)
default : print("no idea")
}
} else {
print("no matching objCType")
}
Source: Type Encodings
NSNumber arithmetic
If you want to perform arithmetic the best bet would be using an NSDecimalNumber.
NSDecimalNumber have methods to perform arithmetic operations like :
– decimalNumberByAdding:
– decimalNumberBySubtracting:
– decimalNumberByMultiplyingBy:
– decimalNumberByDividingBy:
– decimalNumberByRaisingToPower:
– decimalNumberByMultiplyingByPowerOf10:
– decimalNumberByAdding:withBehavior:
– decimalNumberBySubtracting:withBehavior:
– decimalNumberByMultiplyingBy:withBehavior:
– decimalNumberByDividingBy:withBehavior:
– decimalNumberByRaisingToPower:withBehavior:
– decimalNumberByMultiplyingByPowerOf10:withBehavior:
And since NSDecimalNumber extends NSNumber it also have all methods of an NSNumber, so i think that you could use it in your case without any problem.
NSNumber object of type long
The answer is simple... the documentation for objCType says:
Special Considerations
The returned type does not necessarily match the method the receiver
was created with.
Related Topics
How to Express Strings in Swift Using Unicode Hexadecimal Values (Utf-16)
Fbsdkaccesstoken Currentaccesstoken Nil After Quitting App
Searchdisplaycontroller Deprecated in iOS 8
How to Send Multiple Parameterts to PHP Server in Http Post
Hide Keyboard When Scroll Uitableview
Uifont - How to Get System Thin Font
Canopenurl - This App Is Not Allowed to Query for Scheme Instragram
Xcode Error on Simulator: Mgisdeviceoneoftype Is Not Supported on This Platform
Where and When to Get Data for Watch Complication
Avcapturesession Audio Doesn't Work for Long Videos
Conditionally Import a Framework (Such as Speech) Based on iOS Version in Swift
Uitableview Auto Resizing Row Constraint Breaking Mysteriously on iPhone 6Plus
iPhone Different Screen Sizes in Flash? (Getting Black Bars)
Switching Viewcontrollers with Uisegmentedcontrol in iOS5
How to Draw a Circle in iOS Swift