Search code examples
iosswiftcore-bluetooth

NSString returns null


I am using CoreBluetooth library in Swift and I want to read what am I receiving from peripheral in Characteristic. When I convert characteristic's value to NSString it returns nil always. Do you know why ? I think is because of encoding, because I have a Characteristic where I can read and write and when I write something to it I can Read what I wrote. When I write the value of Characteristic is 36 if I write 6 and this code works. If I only want to Read a characteristic the code does not work.

This is what my characteristic contains

<CBCharacteristic: 0x1700a2a60, UUID = FFF2, properties = 0x2, value = <02>, notifying = NO>

And this is the code

    func peripheral(_ peripheral: CBPeripheral, didUpdateValueFor characteristic: CBCharacteristic, error: Error?) {

        if error != nil {
            print("Error on updating value on characteristic: \(characteristic) - \(String(describing: error?.localizedDescription))")
            return
        }


        print(characteristic.value!)
        print(NSString(data: characteristic.value!, encoding: String.Encoding.utf8.rawValue)!).   //HERE IS NULL

        guard let stringFromData = NSString(data: characteristic.value!, encoding: String.Encoding.utf8.rawValue) else
        {
            print("Invalid data")
            return
        }

     //ALSO HERE stringFromData IS NULL

}

Solution

  • The value property of CBCharacteristic may contain binary data encoded in thousands of formats defined by its uuid. For example, it may be one of the signed/unsigned integers of size 8-bit, 16-bit, 32-bit or 64-bit. Or 7-byte date and time, or length-preceded UTF-16(LE) String, or... And their combination may be contained.

    (A complex example, decoding Weight Measurement (UUID= 2A9D) here.)

    It may not be a simple string, so NSString.init(data:encoding:) (or String.init(data:encoding:) may not work.

    You need to get your String representation of value for each uuid. You may need to write something like this:

    func peripheral(_ peripheral: CBPeripheral, didUpdateValueFor characteristic: CBCharacteristic, error: Error?) {
    
        if error != nil {
            print("Error on updating value on characteristic: \(characteristic) - \(error!.localizedDescription))")
            return
        }
        guard let data = characteristic.value else {
            print("characteristic.value is nil")
            return
        }
        let uuidStr = characteristic.uuid.uuidString
        let stringFromData: String
        switch uuidStr {
        case "FFF2":
            //I do not know the UUID: FFF2, but seems you prefer it in hexadecimal
            stringFromData = String(format: "%02X", data[0])
        //Add other `case`s for other `uuid`s you want to show...
        //case "XXXX":
        //    stringFromData = ...
        //...
        default:
            stringFromData = "Unsupported UUID: \(uuidStr), data:\(data as NSData)"
        }
        print(stringFromData)
    }