Swift 3: Serializing Swift structs to JSON

It was yesterday when I was reading my news feed and I came across this awesome article on serializing Swift structs to JSON. It’s not just the practicality of it, I also liked the way it’s coded since I ♥️ using protocol extensions for such stuff.

Toying with Swift 3 later that day, I decided to play with the concept in a Swift 3 playground. I’ve got it working quite quickly, but I had found that it lacks support for serializing arrays and dictionaries so I added that and you can find the result in the following gist. You can copy/paste it in a new playground and, if you do so, you can check what Xcode’s Editor > Show Rendered Markup menu option has to offer 🙂

5 thoughts on “Swift 3: Serializing Swift structs to JSON”

  1. Hey
    Great article. I tried to adapt the code for the latest version of the Swift, but I failed. I fight with the types. Have you tried to change the code so that it works with the new Swift?
    Regards
    Luke

  2. I see the trick is in that Mirror(reflecting: …).children thing. My question is: can’t be just a generic JSONSerializer that receives an instance of AnyObject, submit that instance to reflection via Mirror (rather than reflecting on itself), produce the same output?

    That way you lift the restriction for objects to extend JSONSerializable. They can just come as they are. I’m gonna try myself. Unsure if reflection acts on private fields because being able to keep properties immutable, while still being able to serialize the instance at any time would be terrific

  3. Hey there, great article! Very helpful!
    I’m pretty sure this won’t work for nested structs that are _not_ an Array…e.g.:

    struct Book: JSONSerializable {
        var title: String
        var isbn: String
        var pages: Int
    
        var author:Author
        var extra:[String: Any]
    }

    I think this will work:

    extension JSONSerializable {
        var JSONRepresentation: Any {
            var representation = [String: Any]()
            
            for case let (label?, value) in Mirror(reflecting: self).children {
                
                switch value {
                    
                case let value as Dictionary:
                    representation[label] = value as AnyObject
                    
                case let value as Array:
                    if let val = value as? [JSONSerializable] {
                        representation[label] = val.map({ $0.JSONRepresentation as AnyObject }) as AnyObject
                    } else {
                        representation[label] = value as AnyObject
                    }
                    
                case let value as JSONSerializable:
                    representation[label] = (value as JSONSerializable).JSONRepresentation
    
                case let value as AnyObject:
                    representation[label] = value as AnyObject
                    
                default:
                    // Ignore any unserializable properties
                    // TODO: or...should it throw()?
                    break
    
                }
            }
            return representation as Any
        }
    }
  4. Good work!

    I use the code in one of my Apps to Transfer data 😉

Leave a Reply

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