Search code examples
iosswift3nsjsonserialization

Convert swift object (with nested objects) to JSON data in a pure Swift 3 way


I am trying to convert a swift object to JSON, I have seen these SO questions 1 & 2, but I could not apply it to my code.

I have a swift object of type [String : DailyTimes] which I would like to convert it back to JSON data in a pure Swift 3 way, without any libraries.

Below is my custom class:

class AvailabilityTimes:{

    struct Times{
        var startTime : String?
        var endTime   : String?


    }

    struct DailyTimes{
        let weekday : String
        var available : Bool
        var times = [Times]()
        mutating func update(times: [Times]){
            self.times = times
        }

    }
}

The converted JSON data (from Swift object) would look something like this:

[
     "Monday": [ "weekday" : "Monday",
                 "available" : true,
                 "times": [
                     ["startTime": "9:00 AM", "endTime": "1:30 PM" ],
                     ["startTime": "2:30 PM", "endTime": "6:00 PM" ],
                     ["startTime": "7:30 PM", "endTime": "9:00 PM" ]
                 ]
     ],
     "Tuesday": [ "weekday" : "Tuesday",
                 "available" : true,
                 "times": [
                     ["startTime": "9:00 AM", "endTime": "6:00 PM" ]
                 ]
                 ]
     ]

My unsuccessful attempt to convert [String : DailyTimes] to JSON data

Step 1: Added convertToDictionary function in both structs.

class AvailabilityTimes:{

    struct Times{
        var startTime : String?
        var endTime   : String?

        func convertToDictionary() -> Dictionary<String, Any> {
            return [
                "startTime" : self.startTime,
                "endTime"   : self.endTime
            ]
        }
    }

    struct DailyTimes{
        let weekday : String
        var available : Bool
        var times = [Times]()
        mutating func update(times: [Times]){
            self.times = times
        }

        func convertToDictionary() -> Dictionary<String, Any> {
            return [
                "weekday"   : self.weekday,
                "available" : self.available,
                "times"     : self.times
            ]
        }

    }
} 

This is where I am unsuccessfully trying to convert to JSON data.

Step 2: Function that converts to JSON data

func convertTimesObjectToJSON(timesObject: [String : DailyTimes]){

                for (key, value) in timesObject{

                    let dictionary =  value.convertToDictionary

                    print("dictionary", dictionary)
                    do{
                        let theJSONData = try JSONSerialization.data(withJSONObject: dictionary, options: .prettyPrinted)
                    } catch let error{
                        print("error: \(error)")
                    }



                }

            }

Solution

  • This method:

    JSONSerialization.data(withJSONObject: dictionary, options: .prettyPrinted)
    

    requires that dictionary to be a "property list". And a this:

            [
                "weekday"   : self.weekday,
                "available" : self.available,
                "times"     : self.times
            ]
    

    Is not a property list.

    Why? Because self.times is of type [Times], which is not a property list type. You need to call self.times.map{$0.convertToDictionary()) here so as to convert times to a property list.

    func convertToDictionary() -> Dictionary<String, Any> {
        return [
            "weekday"   : self.weekday,
            "available" : self.available,
            "times"     : self.times.map{$0.convertToDictionary())
        ]
    }