Objective-C中的NSNumber numberWithLongLong创建整数

3
当我尝试使用numberWithLongLong创建NSNumber时,如果数字大于-2且小于13,则返回一个被强制转换为(int)的数字。我在跳过该行后查看Xcode调试器时看到了这一点。
为了让问题更加清晰,我正在使用long long值作为纪元日期,最终将使用BSON进行序列化并通过网络发送到webservice。该webservice要求日期是Java Long类型。
感谢您的帮助。

你知道sizeof(int) == sizeof(long),它们都是32位的有符号整数吗?参见:https://dev59.com/QnI95IYBdhLWcg3w3yNU - Jeffery Thomas
你实际上遇到了什么问题?与您实际需要处理的NSNumber对象相比,调试器显示的内容并不是非常相关。 - rmaddy
@CarlVeazey 那么,+numberWithLongLong: 返回一个带有 "i" objCType 的 NSNumber 对象? - Jeffery Thomas
@JefferyThomas 是的,我实际上进行了进一步的测试。在运行iOS 5.1设备和6.1模拟器时,它返回“i”。我的Mac运行10.8.3时,它返回“q”。还尝试使用initWithBytes:objCType:,但与惯例相反,即使在NSNumber实例上调用时,它也会返回NSValue。 - Carl Veazey
1
为什么内部存储数字的大小真的很重要呢?我的意思是,只要你能说 [number longLongValue] 并得到正确的值回来...为什么运行时节省几个字节会成为问题呢?这似乎是封装在起作用,我还不明白为什么不能信任它。 - cHao
显示剩余2条评论
3个回答

6
你发现NSNumber(实际上是它的CFNumber对应项)在-1到12之间的整数有缓存。看一下CFNumber.c中的CFNumberCreate函数如何工作。
如果你想强制不使用缓存,则可以通过向CFNumberCreate传递自己的分配器来实现。你需要查看CFAllocator文档。
但要注意,CFNumberCreate手册中说:
“在创建新的CFNumber对象时,theType参数不一定被保留。”
因此,即使你绕过了缓存,你可能仍然不会得到一个objCTypeq(表示long long)的对象。看起来目前的实现将返回q,但这在未来的版本中可能会发生改变。
如果你需要保证objCType返回q,则可以编写自己的NSNumber子类。阅读NSNumber Class Reference中的“子类笔记”(Subclassing Notes)。

你认为 long long x = 1; NSValue *number = [NSValue valueWithBytes:&x objCType:"q"]; 更好吗?是的,它是一个值而不是一个数字,但类型会被保留吗? - Jeffery Thomas
如果您想确保获得一个 objCTypeqNSNumber,您可以编写自己的 NSNumber 子类。 - rob mayoff

3

您可以放心使用您的webservice。

NSNumber将数值(原始类型)包装为对象。如何存储NSNumber的值并不是您需要关注的问题(但有一种方法可以找到它),因为它是一种不透明类型。然而,NSNumber确实维护了一个内部记录所用类型的记录,因此其compare:方法可以精确地遵循C规则,以便比较不同类型的值。

对于整型,您获得的整数值在数学意义上将与您创建NSNumber时完全相同。您可以使用short创建NSNumber,并将其值读回为long long,即使表示方式不同,数学值也将相同。

因此,您可以将整数日期值存储为NSNumber,当您将其作为long long读取时,您将获得正确的值。不需要担心NSNumber在内部的表示方式,事实上,这在未来可能会发生变化。

(至少有一种NSNumber实现可以将值存储为128位整数,这有助于确保有符号和无符号整数的正确语义。此外,由于实数的不确定性,谈论数学上的精确性有些无意义。)


1

等一下,我想我知道你在问什么。试着这样做:

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?


我认为这不会有任何影响...编译器在将其作为参数传递之前,应始终将int强制转换为long long。 - Bryan Chen
@xlc 编译器自动执行的类型转换称为强制转换。请参阅:http://en.wikipedia.org/wiki/Type_conversion#Implicit_type_conversion - Jeffery Thomas

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接