How to Determine the True Data Type of an Nsnumber

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



Leave a reply



Submit