Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Custom JSON data decode using Swift 4 JSONDecoder.DataDecodingStrategy.custom(_:)

Tags:

json

swift4

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

like image 411
Francesco Piraneo G. Avatar asked Dec 13 '25 04:12

Francesco Piraneo G.


1 Answers

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
}

Encoding

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

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.

like image 118
Code Different Avatar answered Dec 15 '25 16:12

Code Different



Donate For Us

If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!