如何将 NSNumbers 的 NSArray 转换为 NSData

发布于 2024-12-09 20:45:08 字数 2380 浏览 4 评论 0原文

我是 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 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(2

财迷小姐 2024-12-16 20:45:08

是的,在这种情况下您不想使用存档器,因为您只是尝试将一组字节转换为 NSData 块。根据您传入的是 NSNumber 数组还是 NSString 数组,您基本上需要循环遍历数组的内容并将数据附加到NSMutableData

假设它是一个 NSNumber 数组,那么类似这样的事情应该可以工作:

NSMutableData *data = [[NSMutableData alloc] initWithCapacity: [msg count]];
for( NSNumber *number in msg) {
    char byte = [number charValue];
    [data appendBytes: &byte length: 1];
}
// .... code that uses data ...
[data release];

如果数字是字符串形式的数值,您可能需要使用 -(int)intValueNSString 的方法来提取数据,然后将其添加到数据中,基本上将上面的内容更改为:

NSMutableData *data = [[NSMutableData alloc] initWithCapacity: [msg count]];
for( NSString *string in msg) {
    char byte = (char)[string intValue];
    [data appendBytes: &byte length: 1];
}
// .... code that uses data ...
[data release];

并且,如果您尝试从字符串中填充字符,那么您需要使用 [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 of NSNumber or an array of NSString, you'll basically need to loop over the contents of the array and append the data to an NSMutableData.

Assuming it's an array of NSNumber, then something like this should work:

NSMutableData *data = [[NSMutableData alloc] initWithCapacity: [msg count]];
for( NSNumber *number in msg) {
    char byte = [number charValue];
    [data appendBytes: &byte length: 1];
}
// .... code that uses data ...
[data release];

If the numbers are numeric values in string form, you'll probably want to use the -(int)intValue method of NSString to pull out the data and then add that to the data, basically changing the above to:

NSMutableData *data = [[NSMutableData alloc] initWithCapacity: [msg count]];
for( NSString *string in msg) {
    char byte = (char)[string intValue];
    [data appendBytes: &byte length: 1];
}
// .... code that uses data ...
[data release];

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 a unichar instead of a char.

眸中客 2024-12-16 20:45:08
- (NSData *)byteArray2Data:(NSArray *)array {
    NSMutableData *data = [NSMutableData data];
    [array enumerateObjectsUsingBlock:^(NSNumber* number, NSUInteger index, BOOL* stop) {
        uint8_t tmp = number.unsignedCharValue;
        [data appendBytes:(void *)(&tmp)length:1];
    }];

    return data;
}

- (NSArray *)byteData2Array:(NSData *)data {
    NSMutableArray *array = [[NSMutableArray alloc] init];
    [data enumerateByteRangesUsingBlock:^(const void *bytes, NSRange byteRange, BOOL *stop) {
        unsigned char *dataBytes = (unsigned char*)bytes;
        for (NSInteger i = 0; i < byteRange.length; i++) {
            [array addObject:[NSNumber numberWithInt:(dataBytes[i]) & 0xff]];
        }
    }];

    return array;
}
- (NSData *)byteArray2Data:(NSArray *)array {
    NSMutableData *data = [NSMutableData data];
    [array enumerateObjectsUsingBlock:^(NSNumber* number, NSUInteger index, BOOL* stop) {
        uint8_t tmp = number.unsignedCharValue;
        [data appendBytes:(void *)(&tmp)length:1];
    }];

    return data;
}

- (NSArray *)byteData2Array:(NSData *)data {
    NSMutableArray *array = [[NSMutableArray alloc] init];
    [data enumerateByteRangesUsingBlock:^(const void *bytes, NSRange byteRange, BOOL *stop) {
        unsigned char *dataBytes = (unsigned char*)bytes;
        for (NSInteger i = 0; i < byteRange.length; i++) {
            [array addObject:[NSNumber numberWithInt:(dataBytes[i]) & 0xff]];
        }
    }];

    return array;
}
~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文