如何使用按位运算符将带有NSData字节的Obj-C方法转换为Swift

时间:2018-06-01 18:18:09

标签: objective-c swift nsdata crc

我试图将Objective C方法转换为Swift,但为了做到这一点,我需要一些帮助来理解正在发生的事情。

对于上下文,此方法的输入以NSString开头,然后使用utf8编码转换为NSData对象。然后将此数据对象的字节传递给方法(message参数)。

然后,此方法的返回值通过writeData发送到CBPeripheral的某个特征。

这是我理解的内容(从Swift的角度来看)。

  • 传入的消息是UInt8字节数组:[UInt8]
  • 将3个变量创建为UInt32个值; crcValbyteValmask
  • 然后将
  • crcVal设置为UInt32类型
  • 的最大值
  • 然后循环传入的UInt8字节数组中的每个字节,并执行某种操作以生成并附加到最​​终用于发送的crcVal值的最终结果CoreBluetooth对writeData的{​​{1}}命令。

我对按位运算符不是很扎实,或者为什么下面的方法正在做它正在做的事情,因为没有文档。有人可以帮助清理这部分的任何或所有部分吗?我希望写一个Swift等效版本的方法。谢谢。

CBPeripheral

2 个答案:

答案 0 :(得分:4)

不是从头开始编写实现,为什么不使用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中的字节数。实现具有不同的签名并返回稍微不同的类型,但它们都给出相同的结果。

答案 1 :(得分:1)

对于计算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