為什么需要NSNumber?
NSArray,NSDictionary等集合類,只能添加對象,如int a = 100
這樣的純值變量無法添加;
相對應(yīng)的,NSUserDefaults,F(xiàn)MDB數(shù)據(jù)庫等數(shù)據(jù)保存框架,也要求對象,無法保存純值;
因此,我們常用的純數(shù)值,需要一個“包裝”,以方便其它類作為對象存儲和轉(zhuǎn)換,NSNumber 就是這樣的類。
NSNumber是Foundation框架內(nèi)置的類,它的類層級如下
- NSObject
- NSValue
- NSNumber
可以看出NSNumber繼承自NSValue,提供數(shù)值對象,作為純C類型(數(shù)值)的封裝,包括有符號和無符號的char, short int, int, long int, long long int, float, double以及 BOOL值。
封包(值->對象)
使用字面量是最方便的封包方式:
NSArray *nums = @[@1, @2, @3]; //數(shù)值前加@標(biāo)記即可
NSNumber *aNumber = @0xff; //可以使用16進制聲明
@0.2f; // 聲明浮點數(shù)
@YES; // 聲明BOOL
int i = 100;
NSNumber *numObj = @(i); // 封裝C變量
這里注意,16進制默認(rèn)是無符號整形,如果需要符號數(shù),只能使用:
NSNumber *aNumber = @0xff;
NSLog(@"%@", aCharObj.stringValue);
// 輸出為`255`
NSNumber *aCharObj = [[NSNumber alloc] initWithChar:0xFF];
NSLog(@"%@", aCharObj.stringValue);
// 輸出為`-1`
當(dāng)然,有符號數(shù)可以直接用@-1
聲明
解包 (對象->值)
每種數(shù)值類型都有對應(yīng)的取值方法,形如boolValue
,這里有幾個注意點:
-
intValue
和integerValue
并不完全等價,具體差別請關(guān)注筆者后續(xù)系列文章。 - 不同類型可交叉調(diào)用取值方法,隱含著精度轉(zhuǎn)換,需要當(dāng)心轉(zhuǎn)換時的精度損失。如:
NSNumber *floatObj = @0.02;
NSLog(@"%d", [floatObj intValue]); // 得到的是0
不過不用擔(dān)心比較時的精度丟失,因為int類型會轉(zhuǎn)換為double類型再做比較,只要記住低精度默認(rèn)轉(zhuǎn)換為高精度即可。
比較
NSNumber *a = @1;
NSNumber *b = @1;
if (a > b) {
NSLog(@"a > b");
}
if (a < b){
NSLog(@"a < b");
}
if (a == b) {
NSLog(@"a == b");
}
用比較運算符可以正常比較兩個NSNumber對象存儲的值的大小,與調(diào)用比較方法是等價的:
if ( [a compare:b] == NSOrderedAscending) { //等價于 a < b
NSLog(@"a < b");
}
if ([a isEqualToNumber: b]) {
NSLog(@"a == b");
}
類型判斷
正如上面解包時提到的,如果不知道一個NSNumber存儲的原始類型,取值時就有可能損失精度,我們可以用以下方法避免:
- (const char *)objCType
NSLog(@"c type is %s", [@0.2f objCType]);
返回值是一個純C字符串, 只有一個字符,含義如下:
字符 | 值類型 |
---|---|
'c' | char |
'i' | int |
's' | short |
'l' | long |
'q' | long long |
'C' | unsigned char |
'I' | unsigned int |
'S' | unsigned short |
'L' | unsigned long |
'Q' | unsigned long long |
'f' | float |
'd' | double |
以上類型不需要記憶,使用 @enable即可,這里提供一個判斷NSNumber 類型的Sample:
if ([value isKindOfClass:[NSNumber class]]) {
if (strcmp([value objCType], @encode(float)) == 0) {
[cell.detailTextLabel.text = [NSString stringWithFormat:@"%.3f", [value floatValue]]];
}
else
if (strcmp([value objCType], @encode(double)) == 0) {
[self.subTitleString appendString:[NSString stringWithFormat:@"%.3f", [value floatValue]]];
}
else
if (strcmp([value objCType], @encode(int)) == 0) {
[self.subTitleString appendString:[NSString stringWithFormat:@"%d", [value intValue]]];
}
else
[self.subTitleString appendString: [NSString stringWithFormat:@"%d", [value intValue]]];
}
NSNumber 不能做什么
無法做計算,如 a + b
小技巧
利用stringValue
快速轉(zhuǎn)換數(shù)值為字符串
// 假設(shè)已獲得NSIndexPath類型的indexPath值
UILabel *titleLabel = [[UILabel alloc] initWithFrame:CGRectMake(0.0, 0.0, 60.0, 30.0)];
titleLabel.text = @(indexPath.row).stringValue;
你可以嘗試用NSString 的stringWithFormat
方法完成同樣的轉(zhuǎn)換,比較其中差異。