之前在學(xué)習(xí)C語言的時(shí)候課堂上,老師就強(qiáng)調(diào),不能使用float類型的數(shù)字進(jìn)行相等比較判斷。這個(gè)也確實(shí)聽進(jìn)去了,也明白原因是float是存儲是不精確的。但是真正開發(fā)實(shí)踐的時(shí)候,或許只有出問題了,才會醒悟:哦,原來是這樣。這個(gè)問題在高大上的OC上同樣存在,稍不注意就會出現(xiàn)問題。
iOS開發(fā)中,接受后臺的響應(yīng),然后轉(zhuǎn)化為模型對象,最終轉(zhuǎn)化為NSString對象,然后控件顯示出來。這一切都是那么的自然那么的熟悉。
一個(gè)數(shù)字,可以定義為number類型,也可以定義為字符串問題。如果后臺返回的是字符串類型。在iOS json序列化的時(shí)候,會把字符串類型轉(zhuǎn)化為NSString對象,這個(gè)一點(diǎn)問題沒有。但是如果后臺返回的是number類型。json序列化會將number類型轉(zhuǎn)化為NSNumber對象。使用的時(shí)候,想當(dāng)然的會將NSNumber轉(zhuǎn)化為NSString對象。這樣做很自然啊,沒有問題,也用一兩個(gè)數(shù)字測試了,轉(zhuǎn)化是精確的。測試那邊也測試通過了,然后產(chǎn)品上線了。最終,還是出現(xiàn)了問題。不說大數(shù),就10以內(nèi)的吧。有這么多的轉(zhuǎn)換不精確。(如下圖)不信你可以試一下,讓后臺定義double類型數(shù)據(jù)66.6,你轉(zhuǎn)化為字符串會發(fā)現(xiàn)就是66.59999999999999。測試發(fā)現(xiàn)double轉(zhuǎn)化為NSNumber的時(shí)候就會出現(xiàn)問題。double表示的字面值和其存儲的值一般是不一樣的,轉(zhuǎn)化為NSNumber之后,有很大一些數(shù)字,在NSNumber的stringValue上會出錯(cuò)。
NSString* json = @"{\"number\":66.6}";
NSData* data = [json dataUsingEncoding:NSUTF8StringEncoding];
NSDictionary* dic = [NSJSONSerialization JSONObjectWithData:data options:NSJSONReadingMutableLeaves error:nil];
id object = dic[@"number"];
NSLog(@"%@",[object class]);
NSLog(@"%@",object);
打印結(jié)果
__NSCFNumber
66.59999999999999

解決方法可以是把取String的doubleValue,然后再.2f保留兩位小數(shù)進(jìn)行構(gòu)造字符串。千萬不能取floatValue,floatValue在大于15萬的浮點(diǎn)數(shù)字就會出現(xiàn)不精確了(筆者做過遍歷測試)。而doubleValue在數(shù)十億的范圍內(nèi)都是字面上精確的。
根本解決方法還是勸后臺的同事把請求返回的數(shù)據(jù)全部設(shè)置為String類型
如果涉及到計(jì)算的問題,那就只得乖乖轉(zhuǎn)化為NSDecimalNumber對象了。