我正在使用Objective-C,我需要将NSArray中的int添加到NSMutableData(我正在准备通过连接发送数据)。如果我用NSNumber包装int,然后将它们添加到NSMutableData,我怎么能找出NSNumber int中有多少字节?是否有可能使用sizeof(),因为根据Apple文档,“NSNumber是NSValue的子类,它提供任何C标量(数字)类型的值。”?
示例:
NSNumber *numero = [[NSNumber alloc] initWithInt:5];
NSMutableData *data = [[NSMutableData alloc] initWithCapacity:0];
[data appendBytes:numero length:sizeof(numero)];
答案 0 :(得分:6)
numero不是数值,它是指向代表数值的对象的指针。您要做的事情将无法工作,大小将始终等于指针(32位平台为4,64位为8),并且您将向数据添加一些垃圾指针值而不是数字。
即使您尝试取消引用它,也无法直接访问支持NSNumber的字节并期望它能够正常工作。发生了什么是内部实现细节,可能因版本而异,甚至可能在同一版本的不同配置之间(32位vs 64位,iPhone vs Mac OS X,arm vs i386 vs PPC)。只需将字节打包并通过网络发送它们可能会导致在另一端无法正确反序列化,即使您设法获得实际数据。
你真的需要想出一个可以放入数据的整数编码,然后打包并解压缩NSNumbers。类似的东西:
NSNumber *myNumber = ... //(get a value somehow)
int32_t myInteger = [myNumber integerValue]; //Get the integerValue out of the number
int32_t networkInteger = htonl(myInteger); //Convert the integer to network endian
[data appendBytes:&networkInteger sizeof(networkInteger)]; //stuff it into the data
在接收端,然后获取整数并使用numberWithInteger重新创建一个NSNumber:在使用ntohl将其转换为本机主机格式之后。
如果您尝试发送最少的表示等,可能需要更多的工作。
另一种选择是使用NSCoder子类并告诉NSNumber使用你的编码器对自己进行编码,因为这将是平台中立的,但是对于你想要做的事情可能有点过分。
答案 1 :(得分:2)
首先,NSNumber * numero是“指向NSNumber类型的指针”,NSNumber类型是Objective-C对象。一般来说,除非在文档中的某处特别说明,否则面向对象编程中的经验法则是“对象选择如何表示其内部状态的内部细节对于对象实现是私有的,应该被视为黑色框。”同样,除非文档说你可以做其他事情,否则你不能假设NSNumber使用int
的C基元类型来存储你给它的int
值。
以下是您appendBytes:numero
时“幕后”内容的粗略近似值:
typedef struct {
Class isa;
double dbl;
long long ll;
} NSNumber;
NSNumber *numero = malloc(sizeof(NSNumber));
memset(numero, 0, sizeof(NSNumber));
numero->isa = objc_getClass("NSNumber");
void *bytes = malloc(1024);
memcpy(bytes, numero, sizeof(numero)); // sizeof(numero) == sizeof(void *)
这使得更加清楚的是,您附加到NSMutableData
对象data
的内容是numero
所指向的前四个字节(对于Obj-C中的对象总是isa
,对象类)。我怀疑你“想要”做的是将指针复制到实例化对象(numero的值),在这种情况下你应该使用&numero
。这是一个问题,如果您使用GC,因为NSMutableData
使用的缓冲区未被扫描(即,GC系统将不再“看到”该对象并回收它,这几乎是随机的保证稍后崩溃。)
很明显,即使您将指向实例化的NSNumber
对象的指针放入data
,该指针也只在创建它的进程的上下文中有意义。如果将指针发送到另一台计算机,指向该对象的指针就没那么有意义了 - 接收计算机没有(实际的,微不足道的)方式来读取指针指向发送计算机的内存。
由于您似乎遇到了此过程的这一部分问题,因此,我建议您将为您节省无数个小时的调试时遇到的一些非常困难的实现错误:
放弃尝试在机器之间发送原始二进制数据的整个想法,并在它们之间发送简单的ASCII / UTF-8格式信息。
如果您认为这会变得缓慢或低效,那么请允许我建议您先使用简化的ASCII / UTF-8字符串版本来完成所有事情。相信我,调试原始二进制数据并不好玩,当你调试不可避免的问题时,只有NSLog(@"I got: %@", dataString)
的能力值得用它来衡量。然后,一旦所有内容都凝固了,并且你确信你不需要对你需要交换的内容进行任何更改,“端口”(缺少一个更好的词)实现到二进制版本if, 且仅当 时,使用Shark.app进行性能分析将其识别为问题区域。作为参考,这些天我可以在机器之间scp
一个文件,并使传输的千兆链路饱和。对于压缩和加密数据,scp
可能需要做大约五千倍的处理,而不是简单的字符串化,同时传输80MB /秒。然而,在现代硬件上,这几乎不足以让我在菜单栏中运行CPU计量器。