在 iOS 开发中,尤其是涉及蓝牙通信(BLE) 、Socket 数据传输 、设备指令解析 等场景时,处理二进制数据(NSData、十六进制字符串、大小端等
)成为必备技能。
本篇文章将基于 Objective-C,深入介绍如何高效处理二进制数据,并配合实用示例和技巧,帮助你构建稳定可靠的底层数据通信逻辑。
应用场景举例
- 蓝牙设备协议解析(如:
<0x01 0x0A 0xFF>
) - Socket 数据封包解包
- 物联网(IoT)设备指令转换
- 图片/音频等二进制资源校验与处理
基础工具:NSData 与 NSString 互转
一、十六进制字符串 → NSData
objc
/// 将十六进制字符串转换为 NSData
+ (NSData *)transToDataWithString:(NSString *)hexString {
NSMutableData *data = [NSMutableData data];
for (int i = 0; i < hexString.length; i += 2) {
NSString *byteStr = [hexString substringWithRange:NSMakeRange(i, 2)];
unsigned int byteValue;
[[NSScanner scannerWithString:byteStr] scanHexInt:&byteValue];
[data appendBytes:&byteValue length:1];
}
return data;
}
示例:
objc
NSString *hex = @"aabbccdd";
NSData *data = [ParseDataTool transToDataWithString:hex];
NSLog(@"data: %@", data); // 输出:<aa bb cc dd>
二、NSData → 十六进制字符串
objc
/// 将 NSData 转为十六进制字符串
+ (NSString *)transDataToHexString:(NSData *)data {
const unsigned char *dataBuffer = (const unsigned char *)data.bytes;
if (!dataBuffer) return @"";
NSMutableString *hexString = [NSMutableString stringWithCapacity:data.length * 2];
for (int i = 0; i < data.length; ++i) {
[hexString appendFormat:@"%02x", dataBuffer[i]];
}
return [hexString copy];
}
进阶处理:大小端转换(Big Endian vs Little Endian)
为什么需要大小端?
在不同平台(如 iOS vs 嵌入式设备)之间传输数据时,字节顺序可能不同。一个整数 0x12345678
:
- 大端(Big Endian):12 34 56 78
- 小端(Little Endian):78 56 34 12
OC 示例:NSData 转整型(小端)
objc
+ (NSInteger)transLittleEndianDataToInteger:(NSData *)data {
NSInteger value = 0;
for (NSInteger i = 0; i < data.length; i++) {
value |= ((uint8_t *)data.bytes)[i] << (8 * i);
}
return value;
}
示例:
objc
NSData *littleEndianData = [ParseDataTool transToDataWithString:@"78563412"];
NSInteger intValue = [ParseDataTool transLittleEndianDataToInteger:littleEndianData];
// 输出:0x12345678 -> 305419896
数据描述格式化:调试更方便
添加空格分隔(便于人眼阅读)
objc
// "aabbcc" → "aa bb cc"
+ (NSString *)describeBlankFormatWithString:(NSString *)dataString {
NSMutableArray *result = [NSMutableArray array];
for (NSInteger i = 0; i < dataString.length; i += 2) {
NSString *byte = [dataString substringWithRange:NSMakeRange(i, 2)];
[result addObject:byte];
}
return [result componentsJoinedByString:@" "];
}
添加 0x 前缀(用于打印/调试)
objc
// "aabbcc" → "0xaa, 0xbb, 0xcc"
+ (NSString *)describeBytesFormatWithString:(NSString *)dataString {
NSMutableArray *result = [NSMutableArray array];
for (NSInteger i = 0; i < dataString.length; i += 2) {
NSString *byte = [dataString substringWithRange:NSMakeRange(i, 2)];
[result addObject:[NSString stringWithFormat:@"0x%@", byte]];
}
return [result componentsJoinedByString:@", "];
}
字节倒序与逆序指令处理
在解析某些设备协议时,你可能需要将指令内容 倒序排列,如下:
objc
// 输入:"a7000003" 输出:"030000a7"
+ (NSString *)invertedOrderWithStr:(NSString *)str {
NSMutableString *result = [NSMutableString string];
for (NSInteger i = str.length; i >= 2; i -= 2) {
NSString *byte = [str substringWithRange:NSMakeRange(i - 2, 2)];
[result appendString:byte];
}
return [result copy];
}
校验算法:XOR 异或校验
某些协议中结尾校验位采用 XOR 校验,即所有字节异或后得到校验值。
objc
+ (NSString *)xorWithDataString:(NSString *)dataString {
NSData *data = [self transToDataWithString:dataString];
uint8_t result = 0;
const uint8_t *bytes = (const uint8_t *)data.bytes;
for (int i = 0; i < data.length; i++) {
result ^= bytes[i];
}
return [NSString stringWithFormat:@"%02x", result];
}
示例:
objc
NSString *xor = [ParseDataTool xorWithDataString:@"030a2713ea"];
NSLog(@"异或结果:%@", xor); // 输出:XX
实战案例:构造蓝牙写入命令
objc
NSString *cmdHex = @"a10201"; // 指令 + 参数
NSString *xor = [ParseDataTool xorWithDataString:cmdHex];
NSString *finalHex = [cmdHex stringByAppendingString:xor]; // 拼接校验位
NSData *writeData = [ParseDataTool transToDataWithString:finalHex];
// 然后通过蓝牙 writeCharacteristic 发送
最后
本文深入介绍了我在iOS实际工作中使用 Objective-C 处理二进制数据的技巧与实战经验,包括:
NSData
与NSString
的互转- 大小端整数转换
- 指令格式化、倒序、校验
- 真实通信场景中的构造与解析
这些内容在蓝牙、Socket、物联网等开发场景中具有广泛应用。如果你在实际开发中遇到数据解析难题,不妨将这些工具方法封装进自己的项目中,快速定位和解决问题。
如有说错的地方,烦请大家指正,谢谢~