Tutorial: Parsing JSON with Decodable in Swift

Parsing JSON is easy. If your JSON is easy and a well fit for a Decodable. Nevertheless there are some nice tricks to even deal with more complex JSON data e.g. special chars, or spaces within the keys.

Examples

import UIKit

let json = """
    {
     "test": "foobar"
    }
""".data(using: .utf8)!

// Simple struct
struct Test: Decodable {
    let test: String?
}

do {
    // We tell the decode method in which, struct / class the JSON should be unserialized
    let decodedObject = try JSONDecoder().decode(Test.self, from: json)
    
    // We get "foobar here!" That's great and easy.
    print(decodedObject.test)
} catch let jsonError {
    // Of course will never happen!
    print("Damn.")
}

That worked like a charm, we parsed one JSON object into one Test struct. But what about a collection? [{}, ..]

import UIKit

let json = """
    [{
     "test": "foobar"
    }, {
     "test": "foobar2"
    }]
""".data(using: .utf8)!

// Simple struct
struct Test: Decodable {
    let test: String?
}

do {
    // We tell the decode method in which, struct / class the JSON should be unserialized
    // So for collections, we just tell decode, that it's an array of Test
    let collectionOfTest = try JSONDecoder().decode([Test].self, from: json)
    
    // outputs foobar and foobar2. great!
    collectionOfTest.forEach { test in
        print(test.test!)
    }
} catch let jsonError {
    print(jsonError.localizedDescription)
}

Great until now no problems. We learned how to parse arrays and objects. Let’s for something nested.

import UIKit

let json = """
    {
     "test": {
            "label": "foobar2"
        }
    }
""".data(using: .utf8)!

struct NestedTest: Decodable {
    let label: String?
}

// Simple struct
struct Test: Decodable {
    // referencing to itself for example
    // but actually it's only important that the nested struct also implements Decodable!
    let test: NestedTest?
}

do {
    // We tell the decode method in which, struct / class the JSON should be unserialized
    let test = try JSONDecoder().decode(Test.self, from: json)
    
    // Easy, we got foobar2!
    print(test.test?.label)
    
} catch let jsonError {
    print(jsonError.localizedDescription)
}

Easy as well. Good. But what’s happening in case we good strange keys with spaces or special characters.

import UIKit

let json = """
    {
     "test": {
            "la ! bel": "foobar2"
        }
    }
""".data(using: .utf8)!

struct NestedTest: Decodable {
    let label: String?
    
    // That of course doesn't work! So we need a way to map it.
    // let "la ! bel": String?
    // Oh, we are lucky, apple thought about it! You actually can define mappings right here!
    private enum CodingKeys: String, CodingKey {
        // We can simple map here "la ! bel" -> label
        case label = "la ! bel"
    }
}

// Simple struct
struct Test: Decodable {
    // referencing to itself for example
    // but actually it's only important that the nested struct also implements Decodable!
    let test: NestedTest?
}

do {
    // We tell the decode method in which, struct / class the JSON should be unserialized
    let test = try JSONDecoder().decode(Test.self, from: json)
    
    // Easy, we got foobar2!
    print(test.test?.label)
    
} catch let jsonError {
    print(jsonError.localizedDescription)
}

And we are done. That’s probably the important stuff about parsing JSON files in iOS.

I hope I could save someone some time.

Published by Misha

I'm a software engineer coding a lot in PHP, Swift and JS. Also doing quite a lot of DevOps stuff like continues integration and continues delivery.

Leave a comment

Your email address will not be published. Required fields are marked *

This site uses Akismet to reduce spam. Learn how your comment data is processed.

By continuing to use the site, you agree to the use of cookies. more information

The cookie settings on this website are set to "allow cookies" to give you the best browsing experience possible. If you continue to use this website without changing your cookie settings or you click "Accept" below then you are consenting to this.

Close