為什么需要NSNumber瘾杭?
NSArray诅病,NSDictionary等集合類,只能添加對象粥烁,如int a = 100
這樣的純值變量無法添加贤笆;
相對應(yīng)的,NSUserDefaults讨阻,F(xiàn)MDB數(shù)據(jù)庫等數(shù)據(jù)保存框架芥永,也要求對象,無法保存純值钝吮;
因此埋涧,我們常用的純數(shù)值,需要一個(gè)“包裝”奇瘦,以方便其它類作為對象存儲(chǔ)和轉(zhuǎn)換棘催,NSNumber 就是這樣的類。
NSNumber是Foundation框架內(nèi)置的類链患,它的類層級如下
- NSObject
- NSValue
- NSNumber
可以看出NSNumber繼承自NSValue巧鸭,提供數(shù)值對象,作為純C類型(數(shù)值)的封裝麻捻,包括有符號(hào)和無符號(hào)的char, short int, int, long int, long long int, float, double以及 BOOL值纲仍。
封包(值->對象)
使用字面量是最方便的封包方式:
NSArray *nums = @[@1, @2, @3]; //數(shù)值前加@標(biāo)記即可
NSNumber *aNumber = @0xff; //可以使用16進(jìn)制聲明
@0.2f; // 聲明浮點(diǎn)數(shù)
@YES; // 聲明BOOL
int i = 100;
NSNumber *numObj = @(i); // 封裝C變量
這里注意,16進(jìn)制默認(rèn)是無符號(hào)整形贸毕,如果需要符號(hào)數(shù)郑叠,只能使用:
NSNumber *aNumber = @0xff;
NSLog(@"%@", aCharObj.stringValue);
// 輸出為`255`
NSNumber *aCharObj = [[NSNumber alloc] initWithChar:0xFF];
NSLog(@"%@", aCharObj.stringValue);
// 輸出為`-1`
當(dāng)然,有符號(hào)數(shù)可以直接用@-1
聲明
解包 (對象->值)
每種數(shù)值類型都有對應(yīng)的取值方法明棍,形如boolValue
乡革,這里有幾個(gè)注意點(diǎn):
-
intValue
和integerValue
并不完全等價(jià),具體差別請關(guān)注筆者后續(xù)系列文章。 - 不同類型可交叉調(diào)用取值方法沸版,隱含著精度轉(zhuǎn)換嘁傀,需要當(dāng)心轉(zhuǎn)換時(shí)的精度損失。如:
NSNumber *floatObj = @0.02;
NSLog(@"%d", [floatObj intValue]); // 得到的是0
不過不用擔(dān)心比較時(shí)的精度丟失视粮,因?yàn)閕nt類型會(huì)轉(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");
}
用比較運(yùn)算符可以正常比較兩個(gè)NSNumber對象存儲(chǔ)的值的大小蕾殴,與調(diào)用比較方法是等價(jià)的:
if ( [a compare:b] == NSOrderedAscending) { //等價(jià)于 a < b
NSLog(@"a < b");
}
if ([a isEqualToNumber: b]) {
NSLog(@"a == b");
}
類型判斷
正如上面解包時(shí)提到的笑撞,如果不知道一個(gè)NSNumber存儲(chǔ)的原始類型,取值時(shí)就有可能損失精度钓觉,我們可以用以下方法避免:
- (const char *)objCType
NSLog(@"c type is %s", [@0.2f objCType]);
返回值是一個(gè)純C字符串, 只有一個(gè)字符茴肥,含義如下:
字符 | 值類型 |
---|---|
'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即可荡灾,這里提供一個(gè)判斷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 不能做什么
無法做計(jì)算瓤狐,如 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)換,比較其中差異卧晓。