Parsing NSData is crashes - swift

I get this data from BLE, but is crashes on certain values (I think when data is float )
function to get data :
func peripheral(peripheral: CBPeripheral, didUpdateValueForCharacteristic characteristic: CBCharacteristic, error: NSError?) {
print(characteristic); // prints a value always
if characteristic.UUID == UUID_CHAR {
if ( characteristic.value == nil)
{return; }
//***crash is here :
let str:NSString = NSString(data: characteristic.value!, encoding: NSUTF8StringEncoding)!
print ("got::",str);
This will crash when the characteristic is :
<CBCharacteristic: 0x157685860, UUID = FFE1, properties = 0x16, value = <00ff00>, notifying = YES>
and not when its this : (value field here is 00 )
<CBCharacteristic: 0x157685860, UUID = FFE1, properties = 0x16, value = <00>, notifying = YES>
I have tried wrapping it with if let , which did not worked.
ERROR: unexpectedly found nil while unwrapping an Optional value
How would you cast the value to string, knowing it could be a float or integer ?

Don't need to cast to NSString, Then you don't have to forcefully unwrap the result. Try this:
let str = NSString(data: characteristic.value!, encoding: NSUTF8StringEncoding)
Now if the value is not a valid UTF-8 Sequence, You won't get a crash

Related

Why does Swift unexpectedly insert “Optional” at the beginning of stringFromData?

I run this code on an iPad to create virtual BLE peripheral.
It starts advertising.
I run the central on iPhone.
Central detects peripheral and connects and subscribes.
Peripheral log unexpectedly has "Optional" in the log, though it's not in stringFromData.
IMAGE SHOWS stringFromData CONTENT AND LOG.........
class PeripheralViewController: UIViewController {
var packet_to_send = Data()
. . .
func peripheralManager(_ peripheral: CBPeripheralManager, central: CBCentral, didSubscribeTo characteristic: CBCharacteristic) {
os_log("Central subscribed to characteristic")
// Init 1st sim packet:
packet_to_send = ("antenna data chunk " + String( packet_number )).data(using: .utf8)!
let stringFromData = String(data: packet_to_send, encoding: .utf8)
os_log("initial packet_to_send %d bytes = '%s'.", packet_to_send.count, String( describing: stringFromData))
stringFromData is an Optional. When you use String(describing:) to get the description of an Optional, it will be "Optional(yourDescription)" rather than "yourDescription".
You can avoid this by converting the Optional<String> into a String using optional binding or by providing a default value.
let stringFromData = String(data: packet_to_send, encoding: .utf8) ?? ""
os_log("initial packet_to_send %d bytes = '%s'.", packet_to_send.count, stringFromData)

Convert Data? containing bytes to Int in swift 5

I read from a characteristic of a ble peripheral on IoS some data, and when I try to print them, it just says 2 bytes. Looking at the type it is a optional Data type (Data?).
My question is, to convert that value to a readable integer, what is the best as fastest practice in swift 5?
If I try to print characteristic.value it just says "2 bytes". characteristic.value is an optional Data type.
switch characteristic.uuid:
case accelerometerUUID:
if characteristic.value != nil {
let accelValue = ???
print(accelValue)
}
Thank you very much!
Try this:
guard let value = characteristic.value else { return } // This makes it non-optional
let stringInt = String(data: value, encoding: .utf8)
let yourNumber = Int(stringInt)
This is much safer than the example below. The one above should be preferred.
In one line of code:
let yourNumber = Int(String(data: characteristic.value!, encoding: .utf8))
This is unsafe because you are unwrapping a value that might be optional, this can result in a crash.
Hope this helps!

Upgraded from Kanna 2.2.1 to 4.0.2 and getting the same error

I am rewriting a project I found on Github to learn and teach myself how to use swift and pod files. I upgraded Kanna from 2.2.1 to 4.0.2 because I was getting an arm64 error.
With 4.0.2 I am getting the error:
Initializer for conditional binding must have Optional type, not 'HTMLDocument'
Call can throw, but it is not marked with 'try' and the error is not handled
I am unsure about what this error means and how to fix it. It is associated with this if statement:
if let doc = Kanna.HTML(html: htmlText, encoding: String.Encoding.utf8) {
for itemSize in doc.css("option[value^='']") {
let itemSizeText = itemSize.text!.lowercased()
let wishListItemSize = self.websiteInstance!.websiteWishListItem.size!.lowercased()
if itemSizeText.range(of: wishListItemSize) != nil {
print("Found size")
foundItemSize = true
let itemSizeValue = itemSize["value"]
self.websiteInstance!.viewController!.websiteBrowser!.evaluateJavaScript("document.getElementById(\"size-options\").value = \(itemSizeValue!)", completionHandler: nil)
break
}
countSize += 1
}
}
The type signature for the method you are calling is public func HTML(html: String, url: String? = nil, encoding: String.Encoding, option: ParseOption = kDefaultHtmlParseOption) throws -> HTMLDocument. The function returns a non-Optional value, but can throw an error.
You can handle the error by either using the try? keyword to make the function return nil in case an error was thrown and make the optional binding you currently use work like this:
if let doc = try? Kanna.HTML(html: htmlText, encoding: String.Encoding.utf8) {...
or rather use try and put the function call in a do-catch block to see the actual error in case any was thrown.
do {
let doc = Kanna.HTML(html: htmlText, encoding: String.Encoding.utf8)
for itemSize in doc.css("option[value^='']") {
let itemSizeText = itemSize.text!.lowercased()
let wishListItemSize = self.websiteInstance!.websiteWishListItem.size!.lowercased()
if itemSizeText.range(of: wishListItemSize) != nil {
print("Found size")
foundItemSize = true
let itemSizeValue = itemSize["value"]
self.websiteInstance!.viewController!.websiteBrowser!.evaluateJavaScript("document.getElementById(\"size-options\").value = \(itemSizeValue!)", completionHandler: nil)
break
}
countSize += 1
}
} catch {
print(error)
// Handle error
}

Swift :Initializer for conditional binding must have Optional type, not 'String.SubSequence' (aka 'Substring')

I'm working on a little project and I came across this error which I can't find on the Internet.
This is my code:
let bufferRecieved = String(bytesNoCopy: buffer, length: length, encoding: .utf8, freeWhenDone: true)
guard let delimiterFirstIndex = bufferRecieved?.index(of: ":")!,
let name = bufferRecieved![..<delimiterFirstIndex],
let message = bufferRecieved![delimiterFirstIndex...] else {
return nil
}
I get:
Initializer for conditional binding must have Optional type, not 'String.SubSequence' (aka 'Substring') for the two instructions
let name = bufferRecieved![..<delimiterFirstIndex],
let message = bufferRecieved![delimiterFirstIndex...]
What does this error mean and how can I fix it?
name and message aren't Optionals, so there's no need for them to be part of the conditional binding. Just put them after the guard statement:
guard let bufferRecieved = String(bytesNoCopy: buffer, length: length, encoding: .utf8, freeWhenDone: true),
let delimiterFirstIndex = bufferRecieved.index(of: ":") else {
return nil
}
let name = bufferRecieved[..<delimiterFirstIndex]
let message = bufferRecieved[delimiterFirstIndex...]
use(name, message)

RSAUtils Decryption , Converting data to it's original value - Swift

i am trying to encrypt and decrypt a string using RSAUtils swift library, i am having a problem returning the decrypted text to it's original value . this is the code:
let PUBLIC_KEY = "MFwwDQYJKoZIhvcNAQEBBQADSwAwSAJBAJh+/sdLdlVVcM5V5/j/RbwM8SL++Sc3dMqMK1nP73XYKhvO63bxPkWwaY0kwcUU40+QducwjueVOzcPFvHf+fECAwEAAQ=="
let sampleText:String = "WHATS UP"
let encrypted:Data? = RSAUtils.encryptWithRSAPublicKey(sampleText.data(using: String.Encoding.utf8)!, pubkeyBase64: PUBLIC_KEY, keychainTag: "12345")!
let decrypted:Data? = RSAUtils.decryptWithRSAPublicKey(encrypted!, pubkeyBase64: PUBLIC_KEY, keychainTag: "12345")
let encryptedDataText = encrypted!.base64EncodedString(options: NSData.Base64EncodingOptions())
let decryptedDataText = decrypted!.base64EncodedString(options: NSData.Base64EncodingOptions())
I tried to convert the decrypted data to string using this code:
if let string = String(data: decrypted! , encoding: .utf16) {
print(string)
} else {
print("not a valid UTF-16 sequence")
}
But it prints "㺸ꉄ꤈꽹㲞㏯荘뼵鉉큅령嬰ꢤẲ毪쌶⏤ᱼ埡佒�ࡊᩏ⧚㨈؍੯屍" I also tried to decode the base64 value using :
let decodedData = Data(base64Encoded: decryptedDataText)!
let decodedString = String(data: decodedData, encoding: .utf8)!
print(decodedString)
It causes an error
Fatal error: Unexpectedly found nil while unwrapping an O
probably the text is not a valid base64 string.
How can i convert the decrypted data to it's original value.
Thanks.