Edit: I was able to pin down the issue to a MUCH more concentrated field. Although this post here isn't necessarily wrong with its assumptions, Swift 4 base64 String to Data not working due to special character is much more clear and has a Playground example.
I have a string that has to be be serialized into a Dictionary in Swift 4. The app lets users upload data (JSON serialized as Data) and download it later. For the latter, the app does the following with the downloaded data (dlData)
if let rootDict = NSKeyedUnarchiver.unarchiveObject(with: dlData) as? Dictionary<String, Any> {
if let content = rootDict["C"] as? String {
if let data = content.data(using: .utf8, allowLossyConversion: true){
let json = try JSONSerialization.jsonObject(with: data, options: .mutableContainers) as? [String:Any]
...
} else {
print("DATA DIDNT WORK") //gets printed with his data
}
Pretty much every time this has worked fine but recently a user has contacted me that on his iPhone there isn't any data showing up. I've added the else
path and that's where it goes. It doesn't seem to be able to convert this particular string to Data
When I print()
the string, copy the console output and then hardcode it into the method, it works just fine. The string is valid JSON (validated with 3 different online validators), and the JSONSerialization also works. But not in the "live" environment where it uses the downloaded data instead of the hardcoded print()
-representation
Where I think the issue might be is that the Xcode console "cleans up" the string and "bad" characters that might be in it which is why copy-pasting makes it work but a direct download does not. The only weird thing I can spot in the print()
ed string is the replacement character (the � symbol).
dlData > rootDict > content > data > json
Data > Dictionary > string > Data > Dictionary
Isn't the best possible chaining for this task but I am not in the position to change the infrastructure of this system. And because it does work for at least 95% of the users, I think it should work for all of them.
I've tried doing replacingOccurrences(of: "�", with: "?")
but this doesn't affect the string, probably because in the actual string this is no "�" but something else and the "�" only gets displayed because the console doesn't know how else to put it.
I've come across this blog https://natrajbontha.wordpress.com/2017/10/12/replacement-character-in-json-data/ but I would actually prefer to do the cleaning up only when the conversion has already failed once.
The original character at this spot is the American flag emoji and my users could live without having the latest emojis in there but generally, I want emojis to be displayed so replacing all of them isn't a choice.
I've just tried the same in the Playground and it results in the same.
//b64String is dlData but in base64
let decodedData = Data(base64Encoded: b64String)! //works
if let unarchivedDictionary = NSKeyedUnarchiver.unarchiveObject(with: decodedData) as? Dictionary<String, Any> { //works
if let dF = unarchivedDictionary["C"] as? String { //works
print(dF) //prints
if let data = dF.data(using: .utf8, allowLossyConversion: true) { //fails
print(data)
} else {
print("NO DATA") //prints
}
}
}