如何将 NSNumbers 的 NSArray 转换为 NSData
我是 Objective C 的新手,正在修改发送 UDP 数据包的 Titanium 框架的 iOS 模块。该模块目前允许您传入要发送的文本字符串,它会将其转换为字节并通过 UDP 发送到目标 IP 和端口。这很好用,代码如下:
https://github.com/chrisfjones/ titan_module_udp/blob/master/UDPSocketProxy.m
我想要做的是将字节数组而不是字符串传递到发送函数中,然后让它发送。这是 Titanium 代码:
var udp = require('chrisfjones.titanium_module_udp');
var socket = udp.createUDP();
var bytes = [ 100, 15, 132, 53, 14, 246, 0, 0, 0, 0, 196, 209, 1, 1, 0, 10, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 255, 16, 0, 45, 120, 0, 0, 0, 0, 158, 4, 111, 30, 179, 41 ];
socket.send(bytes, "1.2.3.4", 6100);
这是到目前为止的新发送函数:
- (void) sendBytes: (NSArray*) args {
NSArray *msg = (NSArray*)[args objectAtIndex: 0];
NSString *host = [TiUtils stringValue:[args objectAtIndex: 1]];
NSInteger port = [TiUtils intValue: [args objectAtIndex: 2]];
NSLog(@"%@ send bytes: %@ to %@:%i", self, msg, host, port);
struct sockaddr_in destinationAddress;
socklen_t sockaddr_destaddr_len = sizeof(destinationAddress);
memset(&destinationAddress, 0, sockaddr_destaddr_len);
destinationAddress.sin_len = (__uint8_t) sockaddr_destaddr_len;
destinationAddress.sin_family = AF_INET;
destinationAddress.sin_port = htons(port);
destinationAddress.sin_addr.s_addr = inet_addr([host cStringUsingEncoding: NSUTF8StringEncoding]);
NSData *destinationAddressData = [NSData dataWithBytes:&destinationAddress length:sizeof(destinationAddress)];
NSData *data = [NSKeyedArchiver archivedDataWithRootObject:msg];
CFSocketError socket_error = CFSocketSendData(_socket, (CFDataRef) destinationAddressData, (CFDataRef) data, 10);
if (socket_error) {
NSLog(@"socket error: %li", socket_error);
} else {
NSLog(@"sent bytes: '%@' to %@:%i", msg, host, port);
}
}
您会注意到它传递了一个 NSArray。这是因为 Titanium 将我创建的 javascript 数组转换为 NSNumber 对象的 NSArray。我读到这是非常低效的,但它内置于 Titanium 框架中,所以我看不到解决它的方法,所以我希望得到一个关于如何使其与此传递一起工作的答案,而不是关于如何传递的讲座这是低效的。
当我调用新的 send 方法时,它不是发送我传入的 50 个左右字节,而是在wireshark 中看到它实际上传递了超过 1000 个字节。我假设问题出在这一行的转换上:
NSData *data = [NSKeyedArchiver archivedDataWithRootObject:msg];
有人可以帮忙解决如何发送我传入的字节数组吗?谢谢!
I'm new to Objective C and am modifying an iOS module for the Titanium framework which sends UDP packets. The module currently lets you pass in a text string to send, and it will convert it to bytes and send it via UDP to a destination ip and port. This works great and here is the code:
https://github.com/chrisfjones/titanium_module_udp/blob/master/UDPSocketProxy.m
What I want to do is pass a byte array into the send function instead of a string and have it just send it. Here is the Titanium code:
var udp = require('chrisfjones.titanium_module_udp');
var socket = udp.createUDP();
var bytes = [ 100, 15, 132, 53, 14, 246, 0, 0, 0, 0, 196, 209, 1, 1, 0, 10, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 255, 16, 0, 45, 120, 0, 0, 0, 0, 158, 4, 111, 30, 179, 41 ];
socket.send(bytes, "1.2.3.4", 6100);
And here is the new send function so far:
- (void) sendBytes: (NSArray*) args {
NSArray *msg = (NSArray*)[args objectAtIndex: 0];
NSString *host = [TiUtils stringValue:[args objectAtIndex: 1]];
NSInteger port = [TiUtils intValue: [args objectAtIndex: 2]];
NSLog(@"%@ send bytes: %@ to %@:%i", self, msg, host, port);
struct sockaddr_in destinationAddress;
socklen_t sockaddr_destaddr_len = sizeof(destinationAddress);
memset(&destinationAddress, 0, sockaddr_destaddr_len);
destinationAddress.sin_len = (__uint8_t) sockaddr_destaddr_len;
destinationAddress.sin_family = AF_INET;
destinationAddress.sin_port = htons(port);
destinationAddress.sin_addr.s_addr = inet_addr([host cStringUsingEncoding: NSUTF8StringEncoding]);
NSData *destinationAddressData = [NSData dataWithBytes:&destinationAddress length:sizeof(destinationAddress)];
NSData *data = [NSKeyedArchiver archivedDataWithRootObject:msg];
CFSocketError socket_error = CFSocketSendData(_socket, (CFDataRef) destinationAddressData, (CFDataRef) data, 10);
if (socket_error) {
NSLog(@"socket error: %li", socket_error);
} else {
NSLog(@"sent bytes: '%@' to %@:%i", msg, host, port);
}
}
You'll notice that it passes in a NSArray. That is because Titanium converts the javascript array that I create into a NSArray of NSNumber objects. I read that this is terribly inefficient but it's built into the Titanium framework so I don't see a way around it, so I'm hoping for an answer on how to make it work with this getting passed in, not a lecture on how inefficient it is.
When I call the new send method, instead of it sending the 50 or so bytes that I pass in, I can see in wireshark that it is actually passing over 1000 bytes. I'm assuming the issue is with the conversion on this line:
NSData *data = [NSKeyedArchiver archivedDataWithRootObject:msg];
Can someone please help on how to just send the byte array that I pass in? Thanks!
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。
绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论
评论(2)
是的,在这种情况下您不想使用存档器,因为您只是尝试将一组字节转换为
NSData
块。根据您传入的是NSNumber
数组还是NSString
数组,您基本上需要循环遍历数组的内容并将数据附加到NSMutableData
。假设它是一个
NSNumber
数组,那么类似这样的事情应该可以工作:如果数字是字符串形式的数值,您可能需要使用
-(int)intValue
NSString 的方法来提取数据,然后将其添加到数据中,基本上将上面的内容更改为:并且,如果您尝试从字符串中填充字符,那么您需要使用
[string 抓取字符characterAtIndex: 0]
并补偿您将收到unichar
而不是char
的事实。Yes, you don't want to use the archiver in this case, since you're just trying to turn a set of bytes into a block of
NSData
. Depending on whether you are passing in an array ofNSNumber
or an array ofNSString
, you'll basically need to loop over the contents of the array and append the data to anNSMutableData
.Assuming it's an array of
NSNumber
, then something like this should work:If the numbers are numeric values in string form, you'll probably want to use the
-(int)intValue
method ofNSString
to pull out the data and then add that to the data, basically changing the above to:And, if you're trying to stuff the characters from the strings, then you'll need to grab the character using
[string characterAtIndex: 0]
and compensate for the fact that you will be receiving aunichar
instead of achar
.