如何将NSNumbers的NSArray转换为NSData

问题描述 投票:1回答:2

我是Objective C的新手,正在修改用于发送UDP数据包的Titanium框架的iOS模块。该模块当前允许您传递文本字符串进行发送,它将转换为字节,并通过UDP将其发送到目标ip和端口。这很好用,下面是代码:

https://github.com/chrisfjones/titanium_module_udp/blob/master/UDPSocketProxy.m

我想做的是将字节数组而不是字符串传递给send函数,并让它只是发送它。这是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];

有人可以帮忙如何发送我传入的字节数组吗?谢谢!

objective-c ios titanium nsdata titanium-modules
2个回答
3
投票

是的,在这种情况下,您不想使用存档器,因为您只是试图将一组字节转换为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的事实。


0
投票
- (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;
}
© www.soinside.com 2019 - 2024. All rights reserved.