I have a QR code scanner which reads QR codes as a string. There are no options to detect it as a dictionary. So the only solution would be to convert it to a dictionary (i think). Keep in mind I am using swift and using AVFoundation, which is from apple.
This QR code would print out ["test": "test123"] as a string. How would I convert it to a dictionary?
Here's what I've came up with. Output is not dictionary though.
let test = "[\"test\": \"test123\"]"
let data = test.data(using: .utf8)!
do{
let output = try JSONSerialization.jsonObject(with: data, options: .allowFragments) as? [String:String]
print ("\(String(describing: output))")
}
catch {
print (error)
}
Related
I have a class that conforms to NSCoding. I want to convert that class into data, then into a string that can be stored on backend.
The issue is that once it's a converted from a String back to Data it fails to unarchive properly with NSKeyedUnarchiver, so converting to a string must be corrupting the data.
Here's the code:
do {
let data = try NSKeyedArchiver.archivedData(withRootObject: drawItems, requiringSecureCoding: false)
let stringData = String(decoding: data, as: UTF8.self)
print("HERE successfully converted to a string: ", stringData)
let stringBackToData: Data? = stringData.data(using: .utf8)
if let stringBackToData = stringBackToData, let allItems = try NSKeyedUnarchiver.unarchiveTopLevelObjectWithData(stringBackToData) as? [DrawItem] {
print("HERE items: ", allItems)
} else {
print("HERE FAILED to unarchive")
}
catch {
print("Failed: ", error)
}
What is wrong with this string conversion?
The default outputFormat for NSKeyedArchiver is .binary, which is not convertible to or from UTF-8. In your example, String(decoding: data, as: UTF8.self) "repairs" invalid UTF-8 bytes by replacing them with the UTF-8 replacement character (0xFFFD).
This corrupts the archiver data, and prevents it from decoding properly.
If you really can't transmit binary data to your backend as-is, or store it that way, and must convert the data into a string, you have two options:
NSKeyedArchiver has an alternate .outputFormat of .xml, which produces UTF-8 XML data. You can produce this data by creating an archiver and configuring it:
let archiver = NSKeyedArchiver(requiringSecureCoding: false)
archiver.outputFormat = .xml
archiver.encode(drawItems, forKey: NSKeyedArchiveRootObjectKey)
if let error = archiver.error {
// Handle the error. This is the same error that would be produced
// by `NSKeyedArchiver.archivedData(withRootObject:requiringSecureCoding:)`
} else {
let data = archiver.encodedData
// `data` is UTF-8 XML data ready to be transmitted/stored
}
Alternatively, you can continue using the convenience method you are now, but Base64 encode it:
let data = try NSKeyedArchiver.archivedData(withRootObject: drawItems, requiringSecureCoding: false)
let base64EncodedData = data.base64EncodedString()
Which you use is up to you: on its own, the base64-encoded string is shorter than the raw XML data (because the starting binary data is significantly smaller than its equivalent XML), but the XML data does compress significantly better than the base64 data does, and may very well end up smaller. You can test both approaches to see what fits your use-case better.
What I want to do:
I want to get an array from UserDefaults that I saved beforehand and append a custom object to it. Afterwards I want to encode it as a Data-type again and set this as the UserDefaults Key again.
My problem:
The encoding part is what is not working as intended for me.
It says: -[__SwiftValue encodeWithCoder:]: unrecognized selector sent to instance 0x60000011a540
But I do not know how to fix this.
Below is my code for more context:
do {
let decoded = defaults.object(forKey: "ExArray") as! Data
var exo = try NSKeyedUnarchiver.unarchiveTopLevelObjectWithData(decoded) as! [Exerc]
exo.append(datas[indexPath.row])
let enco = try NSKeyedArchiver.archivedData(withRootObject: exo, requiringSecureCoding: false) <- Here is the error
defaults.set(enco, forKey: "ExArray")
} catch {
print("Error encoding custom object NOSEARCHO")
}
This is how Exerc looks:
struct Exerc: Codable {
var title: String
var exID: String
}
Seems like you are not using the archiver features, so why don't you just use the codable?
do {
let key = "ExArray"
let decoded = defaults.data(forKey: key)!
var exo = try JSONDecoder().decode([Exerc].self, from: decoded)
exo.append(datas[indexPath.row])
let enco = try JSONEncoder().encode(exo)
defaults.set(enco, forKey: key)
} catch {
print("Error encoding/decoding custom object NOSEARCHO", error)
}
It just a simple refactored MVP of the original code, but you can even work a bit on this and make it human readable right in the plist file!
can you help me,
I'm facing an issue if the JSON came with multilines like this
"{\"groupId\":\"58\",\"chat\":\"send 2lines\nsecondline\"}"
I'm taking the response from server and convert it with this function
let dataDic = self.convertToDictionary(text: (remoteMessage.appData["message"]! as AnyObject) as! String)
print(dataDic!)
and this is my function
func convertToDictionary(text: String) -> [String: AnyObject]? {
if let data = text.data(using: String.Encoding.utf8) {
do {
let json = try JSONSerialization.jsonObject(with: data, options: .mutableContainers) as? [String:AnyObject]
return json
} catch {
print(error.localizedDescription)
}
}
return nil
}
but the problem came if the code have multilines because it's put \n in the return and
it gives me
The data couldn’t be read because it isn’t in the correct format
Error Domain=NSCocoaErrorDomain Code=3840 "Unescaped control character around character 145." UserInfo={NSDebugDescription=Unescaped control character around character 145.}
You should put an extra "\" before "\n", before parsing your JSON. Try using "replacingOccurencesOf" function.
That way your JSON is formatted before parsing.
I write a little snippet of usual code but found that my code don't return hex data from server with this line of code:
let currentData = try! Data(contentsOf: fullURL!)
print("currentData=", currentData)
And the output:
currentData= 24419 bytes
I tried to use Leo's comment link:
stackoverflow.com/q/39075043/2303865
I got something hex data without spaces, and validator (http://jsonprettyprint.com) can't recognise it and returns null.
Let's try to sort out the different issues here and summarize the
above comments.
The description method
of Data prints only a short summary "NNN bytes", and not a hex dump
as NSData did:
let o = ["foo": "bar"]
let jsonData = try! JSONSerialization.data(withJSONObject: o)
print(jsonData) // 13 bytes
You can get a hex dump by bridging to NSData (source):
print(jsonData as NSData) // <7b22666f 6f223a22 62617222 7d>
or by writing an extension method for Data (How to convert Data to hex string in swift).
But that is actually not the real problem. The JSON validator needs
the JSON as a string, not as a hex dump (source):
print(String(data: jsonData, encoding: .utf8)!) // {"foo":"bar"}
And to de-serialize the JSON data into an object you would need
none of the above and just call
let obj = try JSONSerialization.jsonObject(with: jsonData)
I'm getting dictionary value from server in form of String. Now when I try to use that String, it contains \ before ".
I get below value from my web service:
“\”{\\\”111\\\”:\\\”abc\\\”, \\\”222\\\”:\\\”xyz\\\”}\”
I'm trying to convert this string to NSDictionary. Can you please some one guide me for this. Which is the easiest way to convert this to NSDictionary. My current code is as below, but it's not working
var permValue = perm.value?.stringByReplacingOccurrencesOfString("\\", withString: "")
let data = permValue?.dataUsingEncoding(NSUTF8StringEncoding)
if let dict = try! NSJSONSerialization.JSONObjectWithData(data!, options: []) as? NSDictionary{
print("Permission Dictionary : \(dict)")
}
I'm getting an error while converting data to NSDictionary.
Please help. Any help will be appreciated