【问题标题】:Objective C to Swift code conversion, can't seem to treat bytes correctly in Swift目标 C 到 Swift 代码转换,似乎无法在 Swift 中正确处理字节
【发布时间】:2015-01-14 16:20:39
【问题描述】:

我正在开发一个简单的 Swift 蓝牙心率监测器 iOS 应用程序。我找到了 this 有客观 C 代码的很棒的教程。我已将其转换为 Swift,并且正在从我的心率监测器中获取数据。我的问题是我似乎无法正确访问和转换 Swift 中的字节数据。

这是目标 C 代码:

// Instance method to get the heart rate BPM information
- (void) getHeartBPMData:(CBCharacteristic *)characteristic error:(NSError *)error
{
    // Get the Heart Rate Monitor BPM
    NSData *data = [characteristic value];      // 1
    const uint8_t *reportData = [data bytes];
    uint16_t bpm = 0;

    if ((reportData[0] & 0x01) == 0) {          // 2
        // Retrieve the BPM value for the Heart Rate Monitor
        bpm = reportData[1];
    }
    else {
        bpm = CFSwapInt16LittleToHost(*(uint16_t *)(&reportData[1]));  // 3
    }
    // Display the heart rate value to the UI if no error occurred
    if( (characteristic.value)  || !error ) {   // 4
        self.heartRate = bpm;
        self.heartRateBPM.text = [NSString stringWithFormat:@"%i bpm", bpm];
        self.heartRateBPM.font = [UIFont fontWithName:@"Futura-CondensedMedium" size:28];
        [self doHeartBeat];
        self.pulseTimer = [NSTimer scheduledTimerWithTimeInterval:(60. / self.heartRate) target:self selector:@selector(doHeartBeat) userInfo:nil repeats:NO];
    }
    return;
}

这是 Swift 代码:

func peripheral(peripheral: CBPeripheral!,
    didUpdateValueForCharacteristic characteristic: CBCharacteristic!,
    error: NSError!) -> String
{

    // Get the Heart Rate Monitor BPM
    var data = characteristic.value
    var reportData = data.bytes
    var bpm : UInt16
    var rawByte : UInt8
    var outputString = ""
    rawByte = UInt8(reportData[0])
    bpm = 0

    if ((rawByte & 0x01) == 0) {          // 2
        // Retrieve the BPM value for the Heart Rate Monitor
        bpm = UInt16( reportData[4] )
    }
    else {
        bpm = CFSwapInt16LittleToHost(UInt16(reportData[1]))
    }

    outputString = String(bpm)
    return outputString
}

【问题讨论】:

  • 在转换为 swift 时将reportData[1]; 更改为UInt16( reportData[4] ) 是否有原因?
  • 我的错误。感谢您指出这一点。

标签: ios objective-c swift bluetooth


【解决方案1】:
const uint8_t *reportData = [data bytes];

翻译成

let reportData = UnsafePointer<UInt8>(data.bytes)

然后reportData 的类型为UnsafePointer&lt;UInt8&gt;,您可以像在 (Objective-)C 中一样访问它:

if (reportData[0] & 0x01) == 0 { ... }

接下来,

bpm = reportData[1];

在 Swift 中几乎相同。您必须从 UInt8 显式转换为 UInt16 因为 - 与 (Objective-)C 不同 - Swift 不会在类型之间进行隐式转换:

bpm = UInt16(reportData[1]) 

把它放在一起:

func getHeartBPMData(characteristic: CBCharacteristic!) {
    let data = characteristic.value
    let reportData = UnsafePointer<UInt8>(data.bytes)
    var bpm : UInt16
    if (reportData[0] & 0x01) == 0 {
        bpm = UInt16(reportData[1])
    } else {
        bpm = UnsafePointer<UInt16>(reportData + 1)[0]
        bpm = CFSwapInt16LittleToHost(bpm)
    }

    // ...
}

请注意,您的大多数变量都可以用let 声明为常量,而不是 的var。而不是

bpm = CFSwapInt16LittleToHost(bpm)

您也可以使用可用的littleEndian: 构造函数 对于所有整数类型:

bpm = UInt16(littleEndian: bpm)

Swift 3/4 更新:

func getHeartBPMData(characteristic: CBCharacteristic) {
    guard  let reportData = characteristic.value else {
        return 
    }

    let bpm : UInt16
    if (reportData[0] & 0x01) == 0 {
        bpm = UInt16(reportData[1])
    } else {
        bpm = UInt16(littleEndian: reportData.subdata(in: 1..<3).withUnsafeBytes { $0.pointee } )
    }

    // ...
}

【讨论】:

  • 非常感谢! let reportData = UnsafePointer&lt;UInt8&gt;(data.bytes) 是我需要的真正魔法,但我非常感谢您的细心解释。
  • 工作代码在这里有什么价值:https://github.com/tfenton/SwiftHRM.git
猜你喜欢
  • 2015-10-14
  • 1970-01-01
  • 1970-01-01
  • 2017-09-10
  • 1970-01-01
  • 1970-01-01
  • 2018-10-26
  • 1970-01-01
  • 2018-12-13
相关资源
最近更新 更多