I'm looking for example for JSON custom strategy Data decode with:
JSONDecoder.DataDecodingStrategy.custom(_:)
Does someone has example or link(s) about? Apple documentation doesn't explain too much about.
Thank you very much!
Francesco
Here's a more comprehensive example of custom data encoding and decoding strategy. Let's start with a very simple data model:
struct Model: Codable {
var data: Data
}
Data in Swift is encoded into a string in JSON. The default encoding use Base64 so if you assign data to the bytes that make up the string "Hello world", you will get the following data:
let m = Model(data: "Hello world".data(using: .utf8)!)
let json = try JSONEncoder().encode(m)
let jsonString = String(data: json, encoding: .utf8)!
print(jsonString) // {"data":"SGVsbG8gd29ybGQ="}
But let's say you want to use hex codes instead of Base64. You can write your custom data encoding function:
func customDataEncoder(data: Data, encoder: Encoder) throws {
let str = (0..<data.count).map {
String(data[$0], radix: 16, uppercase: true)
}.joined(separator: " ")
var container = encoder.singleValueContainer()
try container.encode(str)
}
let encoder = JSONEncoder()
encoder.dataEncodingStrategy = .custom(customDataEncoder)
let m = Model(data: "Hello world".data(using: .utf8)!)
let json = try JSONEncoder().encode(m)
let jsonString = String(data: json, encoding: .utf8)!
print(jsonString) // {"data":"48 65 6C 6C 6F 20 77 6F 72 6C 64"}
Decoding is the process of turning a JSON string to Data in Swift. If the string was Base64-encoded, you don't need to do anything else. But since we encoded our Data in hex, you need to provide a custom data decoder:
func customDataDecoder(decoder: Decoder) throws -> Data {
let container = try decoder.singleValueContainer()
let str = try container.decode(String.self)
let bytes = str.components(separatedBy: " ").map {
UInt8($0, radix: 16)!
}
return Data(bytes)
}
let decoder = JSONDecoder()
decoder.dataDecodingStrategy = .custom(customDataDecoder)
let decodedM = try decoder.decode(Model.self, from: json)
print(m.data == decodedM.data) // true
Notes: when I say "Data in Swift is encoded into a string in JSON", it is true most of the times but does not have to be so every time. Nothing prevents you from encoding the property data into something like this:
{
"data": {
"count": 11,
"string": "Hello world",
"hex": "48 65 6C 6C 6F 20 77 6F 72 6C 64"
}
}
Of course, you have to update the custom decoder to match the JSON format.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With