【问题标题】:Objective-C NSNumber numberWithLongLong creates integerObjective-C NSNumber numberWithLongLong 创建整数
【发布时间】:2013-04-13 00:59:20
【问题描述】:

当我尝试使用大于 -2 且小于 13 的数字的 numberWithLongLong 创建 NSNumber 时,它会返回一个转换为 (int) 的数字。

如果我在越过我的线路后查看 Xcode 调试器就会看到这一点。

NSNumber* numberA = [NSNumber numberWithLongLong:-2]; //Debugger shows as (long)-2
NSNumber* numberB = [NSNumber numberWithLongLong:-1]; //Debugger shows as (int)-1
NSNumber* numberC = [NSNumber numberWithLongLong:12]; //Debugger shows as (int)12
NSNumber* numberD = [NSNumber numberWithLongLong:13]; //Debugger shows as (long)13

为了把我的问题放在上下文中,我使用一个 long long 值作为一个纪元日期,我最终将使用 BSON 序列化并通过线路发送到 Web 服务。网络服务要求日期为 java Long。

提前致谢

【问题讨论】:

  • 嗯……你知道sizeof(int) == sizeof(long)。两者都是 32 位有符号整数。见:stackoverflow.com/questions/2107544/…
  • 您可以在问题中添加的其他信息:数字 B 和 C 返回 "i"objCType,而 A 和 D 返回 "q"。当您使用 LL 为数字文字添加后缀或使用 alloc/initWithLongLong: 时,也会发生这种情况。在运行 iOS 5.1 的第三代 iPad 上的调试器中进行了此测试
  • 您实际遇到的问题是什么?与您实际需要对 NSNumber 对象执行的操作相比,调试器显示的内容并不十分相关。
  • @CarlVeazey 所以,+numberWithLongLong: 返回一个带有"i" objCType 的NSNumber 对象?
  • 为什么内部存储的数字大小真的很重要?我的意思是,只要你可以说[number longLongValue] 并得到正确的值...为什么运行时节省几个字节是个问题?这似乎是工作中的封装,我还不明白为什么不应该信任它。

标签: objective-c xcode nsnumber long-long


【解决方案1】:

您发现 NSNumber(实际上,它的 CFNumber 对应物)有一个缓存,用于存储 -1 到 12 之间的整数。看看CFNumber.c 中的CFNumberCreate 函数,看看它是如何工作的。

看起来你可以通过将你自己的分配器传递给CFNumberCreate来强制它不使用缓存。您需要查看CFAllocator 文档。

但请注意,CFNumberCreate 手册是这样说的:

theType 参数在创建新的CFNumber 对象时不一定要保留。

因此,即使您绕过缓存,您也可能无法取回objCTypeq(即long long)的对象。看起来当前的实现将返回 q,但这可能会在未来的版本中发生变化。

如果您需要保证objCType 返回q,您可以编写自己的NSNumber 子类。阅读“Subclassing Notes” in the NSNumber Class Reference

【讨论】:

  • 您认为long long x = 1; NSValue *number = [NSValue valueWithBytes:&x objCType:"q"]; 会更好吗?是的,它是一个值而不是一个数字,但类型不会被保留吗?
  • 如果你想保证你得到一个objCTypeqNSNumber,你可以编写自己的NSNumber 子类。
【解决方案2】:

您可以毫无顾虑地使用您的网络服务。

NSNumber 将数值(原始类型)包装为对象。 NSNumber 如何存储该值并不是您真正关心的问题(但有一种方法可以找到它),它是一种 opaque 类型。然而NSNumber 确实维护了用于创建它的类型的内部记录,因此它的compare: 方法可以遵循C 规则来精确比较不同类型的值。

对于整数类型,在数学意义上,您返回的整数值将与您创建NSNumber 的那个值完全相同。您可以使用short 创建一个NSNumber,并将其值读回为long long,即使表示不同,数学值也会相同。

因此,您可以将积分日期值存储为 NSNumber,当您将其读取为 long long 时,您将获得正确的值。无需担心NSNumber 在内部是如何表示它的,事实上这在未来可能会发生变化。

NSNumber 的至少一种实现可以将值存储为 128 位整数,这有助于确保有符号和无符号整数的正确语义。我还强调了整数类型,就像谈论数学的实数的变幻莫测一样准确度有点没有实际意义。)

【讨论】:

    【解决方案3】:

    等等。我想我知道你在问什么。试试这个方法:

    NSNumber* numberA = [NSNumber numberWithLongLong:-2LL];
    NSNumber* numberB = [NSNumber numberWithLongLong:-1LL];
    NSNumber* numberC = [NSNumber numberWithLongLong:12LL];
    NSNumber* numberD = [NSNumber numberWithLongLong:13LL];
    

    顺便说一句:常量的类型无关紧要,当传递给[NSNumber numberWithLongLong:]时,它将被强制转换为long long


    更新

    根据@robmayoff 的回答,我认为 NSNumber 对您来说并不可靠。你是如何包装你的 BSON 的?有没有办法使用 NSValue 代替 NSNumber?

    【讨论】:

    猜你喜欢
    • 2011-03-27
    • 1970-01-01
    • 1970-01-01
    • 2011-12-28
    • 2012-10-17
    • 2010-10-03
    • 1970-01-01
    • 2014-05-14
    • 2010-12-21
    相关资源
    最近更新 更多