ios – 如何确定NSNumber的真实数据类型?

ios – 如何确定NSNumber的真实数据类型?,第1张

概述考虑以下代码: NSNumber* interchangeId = dict[@"interchangeMarkerLogId"];long long llValue = [interchangeId longLongValue];double dValue = [interchangeId doubleValue];NSNumber* doubleId = [NSNumber number 考虑以下代码:

NSNumber* interchangeID = dict[@"interchangeMarkerLogID"];long long llValue = [interchangeID longLongValue];double dValue = [interchangeID doubleValue];NSNumber* doubleID = [NSNumber numberWithDouble:dValue];long long llDouble = [doubleID longLongValue];if (llValue > 1000000) {    NSLog(@"Have Marker ID = %@,interchangeID = %@,long long value = %lld,doubleNumber = %@,doubleAsll = %lld,CType = %s,longlong = %s",self.ID,interchangeID,llValue,doubleID,llDouble,[interchangeID objCType],@encode(long long));}

结果:

Have Marker ID = (null),interchangeID = 635168520811866143,
long long value = 635168520811866143,doubleNumber = 6.351685208118661e+17,
doubleAsll = 635168520811866112,CType = d,longlong = q

dict来自NSJsONSerialization,原始的JsON源数据是“interchangeID”:635168520811866143.看起来该值的所有18位数都已在NSNumber中捕获,因此它不可能由NSJsONSerialization作为double(其限制为16位十进制数字)累积.然而,objCType报告它是双倍的.

我们在NSNumber的文档中找到了这个:“返回的类型不一定与创建接收器的方法匹配.”显然这是一个“蠢货”(即记录的BUG).

那么我怎样才能确定这个值是一个整数而不是一个浮点值,所以我可以正确地提取它,具有所有可用的精度? (请记住,我有一些合法浮点的其他值,我也需要准确地提取这些值.)

到目前为止,我已经提出了两个解决方案:

第一个,它没有利用NSDecimalNumber的知识 –

Nsstring* numberString = [obj stringValue];BOol fixed = YES;for (int i = 0; i < numberString.length; i++) {    unichar theChar = [numberString characteratIndex:i];    if (theChar != '-' && (theChar < '0' || theChar > '9')) {        fixed = NO;        break;    }}

第二个,假设我们只需要担心NSDecimalNumber对象,并且可以信任来自常规NSNumbers的CType结果 –

if ([obj isKindOfClass:[NSDecimalNumber class]]) {    // Need to determine if integer or floating-point.  NSDecimalNumber is a subclass of NSNumber,but it always reports it's type as double.    NSDecimal decimalStruct = [obj decimalValue];    // The decimal value is usually "compact",so may have a positive exponent even if integer (due to trailing zeros).  "Length" is expressed in terms of 4-digit halfwords.    if (decimalStruct._exponent >= 0 && decimalStruct._exponent + 4 * decimalStruct._length < 20) {        sqlite3_bind_int64(pStmt,IDx,[obj longLongValue]);                }    else {        sqlite3_bind_double(pStmt,[obj doubleValue]);               }}else ... handle regular NSNumber by testing CType.

第二个应该更有效,特别是因为它不需要创建一个新对象,但稍微令人担忧的是它依赖于NSDecimal的“未记录的行为/接口” – 字段的含义没有记录在任何地方(我可以找到)并被称为“私人”.

两者似乎都有效.

虽然稍微考虑一下 – 第二种方法有一些“边界”问题,因为人们不能轻易调整限制以确保最大可能的64位二进制int将“通过”而不会有稍大的损失风险数.

令人难以置信的是,这种方案在某些情况下失败了:

BOol fixed = NO;long long llValue = [obj longLongValue];NSNumber* testNumber = [[NSNumber alloc] initWithLongLong:llValue];if ([testNumber isEqualToNumber:obj]) {    fixed = YES;}

我没有保存该值,但有一个NSNumber基本上不等于它自己 – 值显示相同但不注册为相等(并且可以确定该值起始于整数).

到目前为止,这似乎有效:

BOol fixed = NO;if ([obj isKindOfClass:[NSNumber class]]) {     long long llValue = [obj longLongValue];     NSNumber* testNumber = [[[obj class] alloc] initWithLongLong:llValue];     if ([testNumber isEqualToNumber:obj]) {         fixed = YES;     } }

显然isEqualToNumber在NSNumber和NSDecimalNumber之间不能可靠地工作.

(但赏金仍然是公开的,以获得最佳建议或改进.)

解决方法 简单回答:你做不到.

为了做你要求的事情,你需要自己跟踪确切的类型. NSNumber更像是一个“哑”包装器,因为它可以帮助您以更客观的方式使用标准数字(作为Obj-C对象).仅使用NSNumber,-objCType是您唯一的方法.如果你想要另一种方式,你必须自己做.

以下是一些可能有帮助的其他讨论:

get type of NSNumber

What’s the largest value an NSNumber can store?

Why is longLongValue returning the incorrect value

@L_301_3@

总结

以上是内存溢出为你收集整理的ios – 如何确定NSNumber的真实数据类型?全部内容,希望文章能够帮你解决ios – 如何确定NSNumber的真实数据类型?所遇到的程序开发问题。

如果觉得内存溢出网站内容还不错,欢迎将内存溢出网站推荐给程序员好友。

欢迎分享,转载请注明来源:内存溢出

原文地址: http://outofmemory.cn/web/1076028.html

(0)
打赏 微信扫一扫 微信扫一扫 支付宝扫一扫 支付宝扫一扫
上一篇 2022-05-26
下一篇 2022-05-26

发表评论

登录后才能评论

评论列表(0条)

保存