iOS Swift 工具类:数据转换工具 ParseDataTool 解析
在做智能硬件蓝牙、Socket、协议解析、物联网设备通讯时,我们经常要处理:
- 十六进制字符串互转Data
- 大端 / 小端整数转换
- 字节倒序
- 异或校验
- 安全裁剪二进制数据
之前我写过一个《Objective-C 版的 ParseDataTool 工具类》,这篇文章是在此基础上,给出完整的 Swift 版本实现,并做了一些更"Swifty"的改造,更适合作为 Swift 项目中的通用工具类。
工具类整体结构
我们用一个 final class ParseDataTool 来封装所有静态工具方法,方便在项目中全局调用:
transLittleEndianDataToInteger(_:):小端 Data → IntconvertDataToInteger(_:):大端 Data → InttransDataToHexString(_:):Data → Hex 字符串transToData(hexString:):Hex 字符串 → DatainvertedOrder(_:):按字节倒序convertToDecimal(fromHex:):十六进制字符串 → 十进制 IntdescribeBlankFormat(_:):"aabbcc"→"aa bb cc"describeBytesFormat(_:):"aabbcc"→"0xaa, 0xbb, 0xcc"transStringToBigMode(_:):按字节倒序 = 小端转大端显示convert(data:):Data 字节序翻转numswap(_:):16 位整数字节互换xor(dataString:):字符串按字节异或compareImageData(_:withXORValue:):Data 异或结果对比subData(_:range:):安全裁剪 Data,防止越界崩溃
完整 Swift 版本 ParseDataTool.swift
swift
//
// ParseDataTool.swift
// 数据转换工具类(Swift版)
//
// Created by tb on 2025/12/08.
//
import Foundation
/// 数据转换工具类(Swift 版本)
///
/// 功能:
/// - 十六进制字符串 ↔ Data
/// - 大端 / 小端整数转换
/// - 字节倒序
/// - 异或校验
/// - 安全裁剪 Data
final class ParseDataTool {
// MARK: - 十六进制与整数转换
/// 将小端模式的 Data 转为 Int32 对应的 Int
/// - Parameter data: 原始二进制数据(小端)
/// - Returns: 转换后的 Int 值
static func transLittleEndianDataToInteger(_ data: Data) -> Int {
guard !data.isEmpty else { return 0 }
var value: UInt32 = 0
let count = min(MemoryLayout<UInt32>.size, data.count)
withUnsafeMutableBytes(of: &value) { buffer in
data.copyBytes(to: buffer, count: count)
}
return Int(UInt32(littleEndian: value))
}
/// 将大端模式的 Data 转为 Int32 对应的 Int
/// - Parameter data: 原始二进制数据(大端)
/// - Returns: 转换后的 Int 值
static func convertDataToInteger(_ data: Data) -> Int {
guard !data.isEmpty else { return 0 }
var value: UInt32 = 0
let count = min(MemoryLayout<UInt32>.size, data.count)
withUnsafeMutableBytes(of: &value) { buffer in
data.copyBytes(to: buffer, count: count)
}
return Int(UInt32(bigEndian: value))
}
// MARK: - 十六进制与字符串转换
/// 将 Data 转为十六进制字符串(小写)
/// - Parameter data: 原始二进制数据
/// - Returns: 例如:`<aa bb cc>` -> `"aabbcc"`
static func transDataToHexString(_ data: Data) -> String {
guard !data.isEmpty else { return "" }
return data.map { String(format: "%02x", $0) }.joined()
}
/// 将十六进制字符串转为 Data
/// - Parameter hexString: 例如 `"1234edaced0204ff23"` 或中间带空格的 `"12 34 ed ac"`
/// - Returns: 对应的 Data
static func transToData(hexString: String) -> Data {
let cleanString = hexString.replacingOccurrences(of: " ", with: "")
guard !cleanString.isEmpty, cleanString.count % 2 == 0 else {
return Data()
}
var data = Data(capacity: cleanString.count / 2)
var index = cleanString.startIndex
while index < cleanString.endIndex {
let nextIndex = cleanString.index(index, offsetBy: 2)
let byteString = String(cleanString[index..<nextIndex])
if let byte = UInt8(byteString, radix: 16) {
data.append(byte)
} else {
// 解析失败,返回当前已解析部分(也可以选择直接返回空)
return Data()
}
index = nextIndex
}
return data
}
/// 将十六进制字符串按照每 1 字节(2 个字符)进行倒序
/// - Parameter str: 例如 `"a7000003"` -> `"030000a7"`
/// - Returns: 倒序之后的字符串
static func invertedOrder(_ str: String) -> String {
guard !str.isEmpty, str.count % 2 == 0 else { return "" }
var result = ""
var index = str.endIndex
while index > str.startIndex {
let prevIndex = str.index(index, offsetBy: -2)
let byte = str[prevIndex..<index]
result.append(contentsOf: byte)
index = prevIndex
}
return result
}
/// 将十六进制字符串转为十进制 Int
/// - Parameter hexString: 例如 `"00a1"` -> 161
static func convertToDecimal(fromHex hexString: String) -> Int {
guard !hexString.isEmpty else { return 0 }
return Int(hexString, radix: 16) ?? 0
}
// MARK: - 格式化输出辅助
/// 将纯十六进制字符串转为带空格格式
/// - Example: `"aabbccdd"` -> `"aa bb cc dd"`
static func describeBlankFormat(_ dataString: String) -> String {
guard !dataString.isEmpty else { return "" }
guard dataString.count % 2 == 0 else { return dataString }
var components: [String] = []
var index = dataString.startIndex
while index < dataString.endIndex {
let nextIndex = dataString.index(index, offsetBy: 2)
let byte = String(dataString[index..<nextIndex])
components.append(byte)
index = nextIndex
}
return components.joined(separator: " ")
}
/// 将纯十六进制字符串转为带 0x 前缀、逗号分隔格式
/// - Example: `"aabbccdd"` -> `"0xaa, 0xbb, 0xcc, 0xdd"`
static func describeBytesFormat(_ dataString: String) -> String {
guard !dataString.isEmpty else { return "" }
guard dataString.count % 2 == 0 else { return dataString }
var components: [String] = []
var index = dataString.startIndex
while index < dataString.endIndex {
let nextIndex = dataString.index(index, offsetBy: 2)
let byte = String(dataString[index..<nextIndex])
components.append("0x\(byte)")
index = nextIndex
}
return components.joined(separator: ", ")
}
// MARK: - 大小端与字符串处理
/// 将字符串视为小端十六进制表示,转为大端显示(按字节倒序)
/// - Parameter string: 小端字节序表示的字符串
/// - Returns: 按大端顺序显示的十六进制字符串
static func transStringToBigMode(_ string: String) -> String {
return invertedOrder(string)
}
/// 反转 Data 的字节顺序(大小端转换时可用)
/// - Parameter data: 原始数据
/// - Returns: 字节反转后的数据
static func convert(data: Data) -> Data {
return Data(data.reversed())
}
/// 将 16 位无符号数的高低字节互换
/// - Parameter len: 原始 Int
/// - Returns: 字节交换之后的 UInt16
static func numswap(_ len: Int) -> UInt16 {
let value = UInt16(len)
return (value >> 8) | (value << 8)
}
// MARK: - 异或计算与校验
/// 对十六进制字符串中的每个字节做异或运算
/// - Parameter dataString: 例如 `"030a2713ea"`
/// - Returns: 异或结果,例如 `"5f"`(举例)
static func xor(dataString: String) -> String {
guard !dataString.isEmpty, dataString.count % 2 == 0 else { return "00" }
var xorResult: UInt8 = 0x00
var index = dataString.startIndex
while index < dataString.endIndex {
let nextIndex = dataString.index(index, offsetBy: 2)
let byteStr = String(dataString[index..<nextIndex])
if let byte = UInt8(byteStr, radix: 16) {
xorResult ^= byte
} else {
return "00"
}
index = nextIndex
}
return String(format: "%02x", xorResult)
}
/// 对 Data 的所有字节做异或,再与给定值比较是否一致
/// - Parameters:
/// - imageData: 二进制数据(比如图片原始 Data)
/// - xorValue: 期望的异或结果
/// - Returns: 是否匹配
static func compareImageData(_ imageData: Data, withXORValue xorValue: Int) -> Bool {
guard !imageData.isEmpty else { return false }
var result: UInt8 = 0x00
imageData.forEach { byte in
result ^= byte
}
return result == UInt8(xorValue & 0xFF)
}
// MARK: - 安全的数据裁剪
/// 安全裁剪 Data,如果越界则返回空 Data,而不是崩溃
/// - Parameters:
/// - data: 原始数据
/// - range: NSRange(通常来自外部协议定义)
/// - Returns: 子 Data 或空 Data
static func subData(_ data: Data, range: NSRange) -> Data {
guard !data.isEmpty else { return Data() }
let start = range.location
let end = range.location + range.length
guard start >= 0,
range.length >= 0,
end <= data.count else {
return Data()
}
let swiftRange = start..<end
return data.subdata(in: swiftRange)
}
}
简单使用示例
swift
let hex = "aabbccdd"
// Hex -> Data
let data = ParseDataTool.transToData(hexString: hex)
print("data =", data as NSData)
// Data -> Hex
let hexStr = ParseDataTool.transDataToHexString(data)
print("hexStr =", hexStr) // aabbccdd
// 字节倒序
let inverted = ParseDataTool.invertedOrder(hex)
print("inverted =", inverted) // ddccbbaa
// 可读格式
print(ParseDataTool.describeBlankFormat(hex)) // aa bb cc dd
print(ParseDataTool.describeBytesFormat(hex)) // 0xaa, 0xbb, 0xcc, 0xdd
// 小端 Data -> Int
let littleEndian = ParseDataTool.transToData(hexString: "78563412")
let intValue = ParseDataTool.transLittleEndianDataToInteger(littleEndian)
print("intValue =", intValue) // 305419896 (0x12345678)
这篇文章把我之前在实际开发项目中原来的使用到二进制的相关转换处理,完整迁移成了 Swift 版本 ParseDataTool.swift,同时:
- 保留了原有的所有功能方法;
- 按照 Swift 的习惯使用了
static func、Data、String的安全下标等; - 在不改变语义的前提下,做了一些更"Swift 风格"的封装。
你可以直接在项目中创建一个 ParseDataTool.swift 文件,把上面的代码贴进去就能用.
如有说错的地方欢迎指正,相互学习~