如何使用按位运算符将带有 NSData 字节的 Obj-C 方法转换为 Swift
How to convert an Obj-C method with NSData bytes using bitwise operators to Swift
我正在尝试将 Objective C 方法转换为 Swift,但为了做到这一点,我需要一些帮助来了解发生了什么。
对于上下文,此方法的输入以 NSString
开始,然后转换为具有 utf8 编码的 NSData
对象。然后将此数据对象的字节传递给方法(message
参数)。
此方法的 return 值然后通过 writeData
发送到 CBPeripheral
的某个特征。
这是我的理解(从 Swift 的角度)。
- 传入的消息是一个
UInt8
字节数组:[UInt8]
- 3 个变量被创建为
UInt32
个值; crcVal
、byteVal
和 mask
crcVal
然后设置为 UInt32
类型 的最大值
- 然后循环传入
UInt8
字节数组中的每个字节,并执行某种操作以生成并附加到 crcVal
值的最终结果,该值最终用于通过 CoreBluetooth 的 writeData
命令发送到 CBPeripheral
.
我不是很了解按位运算符或者为什么下面的方法正在做它正在做的事情,因为没有文档。有人可以帮助清理其中的任何或所有部分吗?我希望编写此方法的 Swift 等效版本。谢谢。
- (uint32_t) computeCRC:(uint8_t *)message len:(NSUInteger)msgLen {
uint32_t crcVal = 0, byteVal, mask;
crcVal = 0xFFFFFFFF;
for (int i=0; i<msgLen; i++) {
byteVal = message[i];
crcVal ^= byteVal;
for (int j=7; j>=0; j--) {
mask = -(crcVal&1);
crcVal = (crcVal>>1)^(0xEDB88320 & mask);
}
}
return ~crcVal;
}
与其从头开始编写实现,不如使用 crc32
的 zlib 实现?:
import zlib
func crc32(from data: Data) -> UInt {
return data.withUnsafeBytes { (buffer: UnsafePointer<Bytef>) -> UInt in
return zlib.crc32(0, buffer, uInt(data.count))
}
}
但是,为了帮助您理解位运算:
func computeCRC(message: [UInt8]) -> UInt32 {
var crc: UInt32 = 0xFFFFFFFF
for byte in message {
crc ^= UInt32(byte)
for _ in 0 ..< 8 {
// negation using 2-complement: -x = ~x + 1
// use &+ addition with overflow
let mask = ~(crc & 1) &+ 1
crc = (crc >> 1) ^ (0xEDB88320 & mask)
}
}
return ~crc
}
请注意,我们不需要传递 Swift 中的字节数。这些实现具有不同的签名,return 类型略有不同,但它们都给出相同的结果。
计算CRC16可以使用
import Foundation
extension Data {
enum CRCType {
case MODBUS
case ARC
}
static func crc16(_ data: [UInt8], type: CRCType) -> UInt16? {
if data.isEmpty {
return nil
}
let polynomial: UInt16 = 0xA001 // A001 is the bit reverse of 8005
var accumulator: UInt16
// set the accumulator initial value based on CRC type
if type == .ARC {
accumulator = 0
} else {
// default to MODBUS
accumulator = 0xFFFF
}
// main computation loop
for byte in data {
var tempByte = UInt16(byte)
for _ in 0 ..< 8 {
let temp1 = accumulator & 0x0001
accumulator = accumulator >> 1
let temp2 = tempByte & 0x0001
tempByte = tempByte >> 1
if (temp1 ^ temp2) == 1 {
accumulator = accumulator ^ polynomial
}
}
}
return accumulator
}
}
来源here
我正在尝试将 Objective C 方法转换为 Swift,但为了做到这一点,我需要一些帮助来了解发生了什么。
对于上下文,此方法的输入以 NSString
开始,然后转换为具有 utf8 编码的 NSData
对象。然后将此数据对象的字节传递给方法(message
参数)。
此方法的 return 值然后通过 writeData
发送到 CBPeripheral
的某个特征。
这是我的理解(从 Swift 的角度)。
- 传入的消息是一个
UInt8
字节数组:[UInt8]
- 3 个变量被创建为
UInt32
个值;crcVal
、byteVal
和mask
crcVal
然后设置为UInt32
类型 的最大值
- 然后循环传入
UInt8
字节数组中的每个字节,并执行某种操作以生成并附加到crcVal
值的最终结果,该值最终用于通过 CoreBluetooth 的writeData
命令发送到CBPeripheral
.
我不是很了解按位运算符或者为什么下面的方法正在做它正在做的事情,因为没有文档。有人可以帮助清理其中的任何或所有部分吗?我希望编写此方法的 Swift 等效版本。谢谢。
- (uint32_t) computeCRC:(uint8_t *)message len:(NSUInteger)msgLen {
uint32_t crcVal = 0, byteVal, mask;
crcVal = 0xFFFFFFFF;
for (int i=0; i<msgLen; i++) {
byteVal = message[i];
crcVal ^= byteVal;
for (int j=7; j>=0; j--) {
mask = -(crcVal&1);
crcVal = (crcVal>>1)^(0xEDB88320 & mask);
}
}
return ~crcVal;
}
与其从头开始编写实现,不如使用 crc32
的 zlib 实现?:
import zlib
func crc32(from data: Data) -> UInt {
return data.withUnsafeBytes { (buffer: UnsafePointer<Bytef>) -> UInt in
return zlib.crc32(0, buffer, uInt(data.count))
}
}
但是,为了帮助您理解位运算:
func computeCRC(message: [UInt8]) -> UInt32 {
var crc: UInt32 = 0xFFFFFFFF
for byte in message {
crc ^= UInt32(byte)
for _ in 0 ..< 8 {
// negation using 2-complement: -x = ~x + 1
// use &+ addition with overflow
let mask = ~(crc & 1) &+ 1
crc = (crc >> 1) ^ (0xEDB88320 & mask)
}
}
return ~crc
}
请注意,我们不需要传递 Swift 中的字节数。这些实现具有不同的签名,return 类型略有不同,但它们都给出相同的结果。
计算CRC16可以使用
import Foundation
extension Data {
enum CRCType {
case MODBUS
case ARC
}
static func crc16(_ data: [UInt8], type: CRCType) -> UInt16? {
if data.isEmpty {
return nil
}
let polynomial: UInt16 = 0xA001 // A001 is the bit reverse of 8005
var accumulator: UInt16
// set the accumulator initial value based on CRC type
if type == .ARC {
accumulator = 0
} else {
// default to MODBUS
accumulator = 0xFFFF
}
// main computation loop
for byte in data {
var tempByte = UInt16(byte)
for _ in 0 ..< 8 {
let temp1 = accumulator & 0x0001
accumulator = accumulator >> 1
let temp2 = tempByte & 0x0001
tempByte = tempByte >> 1
if (temp1 ^ temp2) == 1 {
accumulator = accumulator ^ polynomial
}
}
}
return accumulator
}
}
来源here