将NSData转换为NSString会返回随机字符

时间:2013-12-23 07:49:09

标签: ios objective-c nsstring nsdata

我正在开展bluetooth iOS项目,并设法从bluetooth设备获取一些数据。 但是,我正在努力将这些数据转换为有用的数据,例如NSString。每当我尝试NSLog从收到的NSString转换的NSData时,它就是一堆gibberish。输出是:

ēဥ၆䄀

蓝牙设备是来自亚洲制造商的心脏监测器,他们提供了有关如何拨打设备的协议参考。他们在协议参考中提到了这一点:

The PC send 16-byte packets to the device, then the device sent back the 16-byte packets. Except for some special commands, all others can use this communication mode.

谁能告诉我我做错了什么?我尝试了所有我知道的内容,包括Apple文档中的每个编码以及initWithDatainitWithBytes。谢谢!

-(void)peripheral:(CBPeripheral *)peripheral didUpdateValueForCharacteristic:(CBCharacteristic *)characteristic
         error:(NSError *)error {
if (error)
{
    NSLog(@"erorr in read is %@", error.description);
    return;
}
NSData *data= characteristic.value;
 NSString *myString = [[NSString alloc] initWithBytes:[data bytes] length:[data length] encoding:NSUTF16StringEncoding];
NSLog(@"Value from device is %@", myString); //OUTPUT IS ēဥ၆䄀

}

1 个答案:

答案 0 :(得分:3)

这里有一个原始数据的字符串,不能直接转换为人类可读的字符串 - 除非您认为十六进制表示是人类可读的:)

要了解这些数据,您需要手头有一个协议规范,或者准备数小时(有时)反向工程。

这个字节序列可以由标准格式(浮点IEEE 754uint8_tuint16_t ...)甚至专有格式的多个值组成。

与外部世界通信时要考虑的一件重要事情也是endianness(即:多字节格式的“最大”字节是第一个还是最后一个)。

有很多方法可以操纵这些数据。要获得原始的字节数组,您可以这样做:

NSData *rxData = ...
uint8_t *bytes = (uint8_t *)[rxData bytes];

然后如果(例如)第一个字节告诉你字符串保持什么类型的有效负载,你可以切换如下:

switch (bytes[0])
{
    case 0x00:
        //first byte 0x00: do the parsing
        break;

    case 0x01:
        //first byte 0x01: do the parsing
        break;

    // ...

    default:
        break;
}

以下是解析包含以下内容的数据的示例:

字节0:保存一些位编码标志的字节 字节1,2,3,4:32位浮点数 字节5,6:uint16_t

bool bitFlag0;
bool bitFlag1;
bool bitFlag2;
bool bitFlag3;

uint8_t firstByte;
float theFloat;
uint16_t theInteger;

NSData *rxData = ...
uint8_t *bytes = (uint8_t *)[rxData bytes];

// getting the flags
firstByte = bytes[0];

bitFlag0 = firstByte & 0x01;
bitFlag1 = firstByte & 0x02;
bitFlag2 = firstByte & 0x04;
bitFlag3 = firstByte & 0x08;

//getting the float

[[rxData subdataWithRange:NSMakeRange(1, 4)] getBytes:&theFloat length:sizeof(float)];
NSLog (@"the float is &.2f",theFloat);

//getting the unsigned integer

[[data subdataWithRange:NSMakeRange(6, 2)] getBytes:&theInteger length:sizeof(uint16_t)];
NSLog (@"the integer is %u",theInteger);

一个注意事项:根据字节顺序,您可能需要在转换它们之前反转4-float或2-uint16_t字节。转换此字节数组也可以使用联合。

union bytesToFloat
{
    uint8_t b[4];
    float f;
};

然后:

bytesToFloat conv;

//float would be written on bytes b1b2b3b4 in protocol
conv.b[0] = bytes[1]; //or bytes[4] .. endianness!
conv.b[1] = bytes[2]; //or bytes[3] .. endianness!
conv.b[2] = bytes[3]; //or bytes[2] .. endianness!
conv.b[3] = bytes[4]; //or bytes[1] .. endianness!

theFloat = conv.f, 

例如,如果您知道byte6和byte7表示uint16_t值,则可以从原始字节计算它:

value = uint16_t((bytes[6]<<8)+bytes[7]);

或(再次 - 字节顺序):

value = uint16_t((bytes[7]<<8)+bytes[6]);

还有一点需要注意:使用简单sizeof(float)有点冒险,因为浮点数在一个平台上可以是32位而在另一个平台上可以是64位。