How to get NSDictionary from NSData out of bluetooth characteristic in Swift - ios

I try to get NSDictionary from NSData of bluetooth characteristic but I got error message, "NSKeyedUnarchiver initForReadingWithData:]: incomprehensible archive".
peripheralManager send NSDictionary like this to Central.
func peripheralManager(peripheral: CBPeripheralManager!, didReceiveReadRequest request: CBATTRequest!) {
var responseDictonary: Dictionary = [
"id" : 11111,
"name" : "hoge"
]
request.value = NSKeyedArchiver.archivedDataWithRootObject(responseDictonary)
peripheralManager.respondToRequest(request, withResult: CBATTError.Success)
}
CentralManager recieve peripheral like this.
func peripheral(peripheral: CBPeripheral!, didUpdateValueForCharacteristic characteristic: CBCharacteristic!, error: NSError!) {
if (error != nil) {
return
}
if characteristic.UUID == BLECharacteristicUUID {
let data : NSData = characteristic.value
if let recieveDictonary = NSKeyedUnarchiver.unarchiveObjectWithData(data) as? NSDictionary {
var id = recieveDictonary["id"] as Int
var name = recieveDictonary["name"] as String
Tracker.sharedInstance.debug("\(id) \(name)")
}
}
}
Do you have any solutions?

Try doing the following it might help you find the root cause.
Just try to unarchive immediately after you archive in the first method,
It will help you find if there is any issue while archiving itself.
(your archiving code looks fine still make sure its working properly)
check for a nil value for "data" in the second method.

Related

Cannot Convert String to Int from BLE Data

I've spent 3 weeks avoiding this question on Stackover flow but I'm at my wits end.
I don't know why I can create a string manually and convert it into an INT but can't do the same thing from BLE data.
This is my code:
func peripheral(_ peripheral: CBPeripheral, didUpdateValueFor characteristic: CBCharacteristic, error: Error?) {
if error != nil {
print("ERROR ON UPDATING VALUE FOR CHARACTERISTIC: \(characteristic) - \(String(describing: error?.localizedDescription))")
return
}
guard let data = characteristic.value else{
return
}
// let myString = "345345" // I CAN MANUALLY SET A STRING
// let myInt = Int(myString) ?? 2
// print (myInt + 523436) I CAN CONVERT AND USE THIS INT
let weightStringData = swiftDataToString(ESP32Data: data)
func swiftDataToString(ESP32Data:Data) -> String? {
return String(data: data, encoding: .utf8)
}
if let myNewstring = weightStringData{
// print(myNewstring) // THIS PRINTS AS A STRING
let myInt = Int(myNewstring) ?? 2 //THIS DOES NOTHING IT SEEMS OTHER THAN SET THE CONSTANT TO "2"
print (myInt + 9898) //CANT USE THE INT LIKE IN THE ABOVE MANUAL EXAMPLE
}else{
print("Nothing")
}
}
}

How do I handle NSInlineData from Bluetooth scanning?

I want to use data that is passed through Bluetooth scan.
and I want to split and use data from NSInlineData.
I import data via Bluetooth scan as follows.
func centralManager(_ central: CBCentralManager, didDiscover peripheral: CBPeripheral, advertisementData: [String : Any], rssi RSSI: NSNumber) {
if !peripherals.contains(peripheral){
peripherals.append(peripheral)
}
let key = peripheral.identifier.uuidString
let data = advertisementData.description
let rawData = advertisementData
rawData.forEach { (key, val) in
print("\(key) : \(val)")
}
print("uuid: \(key)")
if let previous = datas[key] {
if (previous != data) {
datas.updateValue(data, forKey: key)
rawdatas.updateValue(advertisementData, forKey: key)
}
} else {
datas[key] = data
rawdatas[key] = advertisementData
}
}
The form of the data is as follows.
//uuid: 81DB0A8E-6C47-1ADF-E1C5-3D7D4269D66D
//kCBAdvDataIsConnectable : 0
//kCBAdvDataServiceData : {
// FEAA = <20000200 19400000 03d80000 0000>;
//}
//kCBAdvDataServiceUUIDs : (
// FEAA
//)
The following data were extracted.
if rawdata["kCBAdvDataServiceData"] != nil{
let parseData:NSDictionary = rawdata["kCBAdvDataServiceData"] as! NSDictionary
let data = parseData.allValues.first
// data => optional(<20000200 19400000 03d80000 0000>)
// data type => _NSinlineData
}
I want to take out the number 5,6,7,8(0200) from the data and replace it with a decimal number. I don't know how to handle NSInlineData.
rawdata["kCBAdvDataServiceData"] as? [CBUUID: Data]
NSDictionary is bridged to Dictionary in Swift, which can be represented as [:].
_NSInlineData is the internal type (as indicated by _). It is NSData, which is bridged to Data in Swift.

Could not cast value of type 'Swift.Optional<Swift.AnyObject>' (0x7f9d44715db0) to 'NSArray' (0x60000004f4f8)

I'm trying to check responseObject != nil But It returns always true.
I don't know (How to check nil value for ANY?)
Here is my code:
success: { (operation: AFHTTPRequestOperation?,responseObject: Any?) in
print("view service reponse: \(String(describing: responseObject))")
print("view service reponse: \(responseObject!)")
if responseObject != nil
{
let jsonObjects : NSArray = responseObject as! NSArray
print("All data1 : \(String(describing: jsonObjects))")
for dataDict : Any in jsonObjects {
Crash Issue :
In Log Message:
view service reponse: Optional(nil)
view service reponse: nil
Could not cast value of type 'Swift.Optional' (0x7f9d44715db0) to 'NSArray' (0x60000004f4f8).
(lldb)
I tried below code also,
if let jsonOject = responseObject as? NSArray {
// mean your responce is array type
}
else{
// oterwise your responce in not array
}
But still I got a crash...
Try using Array instead of NSArray.
While migrating to Swift from Objective C people tend to use NSArray and NSDictionary.

ios ble "Characteristic User Description"

Trying to retrieve readable information from an characteristics by using the function:
peripheral.discoverDescriptors(for: characteristic)
Later the delegate method:
func peripheral(_ peripheral: CBPeripheral, didDiscoverDescriptorsFor characteristic: CBCharacteristic, error: Error?)
is called but how can I get the string description? When I read the value from the descriptors it's always nil.
let descriptors = characteristic.descriptors! as [CBDescriptor]
for descriptor in descriptors {
print("\(#function): descriptor = \(descriptor) UUID = \(descriptor.uuid) value = \(descriptor.value)")
}
However, if I'm browsing and connecting with an BLE scanner it can read the characteristic human readable descriptors.
Reading descriptors is a two-step process, much like discovering and then reading characteristics.
Try:
public func peripheral(_ peripheral: CBPeripheral, didDiscoverDescriptorsFor characteristic: CBCharacteristic, error: Error?) {
guard let descriptors = characteristic.descriptors else { return }
for descr in descriptors {
peripheral.readValue(for: descr)
}
}
And then fill in the blanks of:
public func peripheral(_ peripheral: CBPeripheral, didUpdateValueFor descriptor: CBDescriptor, error: Error?) {
switch descriptor.uuid.uuidString {
case CBUUIDCharacteristicExtendedPropertiesString:
guard let properties = descriptor.value as? NSNumber else {
break
}
print(" Extended properties: \(properties)")
case CBUUIDCharacteristicUserDescriptionString:
guard let description = descriptor.value as? NSString else {
break
}
print(" User description: \(description)")
case CBUUIDClientCharacteristicConfigurationString:
guard let clientConfig = descriptor.value as? NSNumber else {
break
}
print(" Client configuration: \(clientConfig)")
case CBUUIDServerCharacteristicConfigurationString:
guard let serverConfig = descriptor.value as? NSNumber else {
break
}
print(" Server configuration: \(serverConfig)")
case CBUUIDCharacteristicFormatString:
guard let format = descriptor.value as? NSData else {
break
}
print(" Format: \(format)")
case CBUUIDCharacteristicAggregateFormatString:
print(" Aggregate Format: (is not documented)")
default:
break
}
}
The string constants and the associated data types came from the overview table here.
In my (limited) experience, descriptors don't reveal anything particularly interesting.

Access PNMessageResult in PubNub Swift

See this link
Based on the following function I am able to receive the response,
func client(client: PubNub!, didReceiveMessage message: PNMessageResult!) {
println(message)
But, I am able to access the data only as message.data which is in the format of PNMessageData.
Even that returns the data in following format:
{
message = "{}";
subscribedChannel = 123;
timetoken = 14392105288780634;}
How will I access the value of message inside the message.data(PNMessageData) ?
I have written simple method to parse PNMessageResult
func client(_ client: PubNub, didReceiveMessage message: PNMessageResult) {
//Message Received on Channel:
let channel = message.data.channel
//Message Received:
guard let messageData = message.data.message as? [String : AnyObject] else { return }
//Event:
guard let event:String = messageData["event"] as? String
let data:AnyObject = messageData["data"] else { return }
guard let dict = data as? NSDictionary else { fatalError("Couldn't parse pubnub message") }
//This will be message in dictionary
let mutableDict = dict.mutableCopy() as! NSMutableDictionary
}
You are very close to accessing the data. The SDK serializes the JSON being received and stores the message as a dictionary on message.data.message which should be a dictionary.
Try this:
func client(client: PubNub!, didReceiveMessage message: PNMessageResult!) {
let dictionary: AnyObject = message.data.message
println(dictionary["accelertiony"]);
println(dictionary["accelerationx"]);
}

Resources