0

I have an array of Field structs that I want to convert to a JSON string.

Field is defined as:

struct Field{

    var name: String
    var center: LatLng
    var perimeter: [LatLng]

    func toDictionary() -> [String : Any]{
        let dict: [String : Any] = ["name":self.name, 
                                    "center":self.center.toDictionary(),
                                    "perimeter": ppsToDictArray()]
        return dict
    }

    fileprivate func ppsToDictArray() -> [Any]{
        var data = [Any]()
        for pp in perimeterPoints{
            data.append(pp.toDictionary())
        }
        return data
    }


}

and LatLng is defined as:

struct LatLng{

    let latitude: Double
    let longitude: Double

    func toDictionary() -> [String : Any]{
        let dict: [String : Any] = ["latitude": self.latitude,
                                    "longitude": self.longitude]
        return dict
    }

}

Here's where I'm trying to convert my array to JSON:

    //selectedFields is a [Field] populated with some Fields
    let dicArray = selectedFields.map{$0.toDictionary()}
    if let data = try? JSONSerialization.data(withJSONObject: dicArray, options: .prettyPrinted){
        let str = String(bytes: data, encoding: .utf8)
        print(str) //Prints a string of "\n\n"
    }

How can I convert such and array to a JSON string? I attempted something along the lines of this answer, but it prints as Optional("[\n\n]")" (I understand why it says "Optional" when printing). I can't seem to get it to work after extrapolating for my structs-within-structs situation. I'm also only about a month into Swift.

EDIT: I edited the above code to represent a more complete example of what I was working on in response to a request to see more work. I didn't include all of that originally because I wasn't asking how to fix my existing code, but more for an example of how to go about the process with nested structs.

Busman
  • 575
  • 2
  • 6
  • 14
  • Let's see your work. – El Tomato Oct 05 '17 at 04:01
  • Pleas try to post more code what you are trying? And what gives you the output `Optional("[\n\n]")`? – Vini App Oct 05 '17 at 04:58
  • https://developer.apple.com/documentation/foundation/archives_and_serialization/encoding_and_decoding_custom_types – Leo Dabus Oct 05 '17 at 05:19
  • 1
    I added my work despite having gotten a solution; I assume that's why it was down-voted. @Leo Dabus that's pretty much the document I needed but couldn't find. Thanks. – Busman Oct 05 '17 at 17:58

1 Answers1

0
struct LatLng {
    let latitude: Double
    let longitude: Double

    func getJSON() -> NSMutableDictionary {
        let dict = NSMutableDictionary()
        dict.setValue(latitude, forKey: "latitude")
        dict.setValue(longitude, forKey: "longitude")
        return dict
    }
}

struct Field {
    var name: String
    var center: LatLng
    var perimeter: [LatLng]

    func getJSON() -> NSMutableDictionary {
        let values = NSMutableDictionary()

        var perimeterArray = Array<NSMutableDictionary>()
        for item in perimeter {
            perimeterArray.append(item.getJSON())
        }

        values.setValue(name, forKey: "name")
        values.setValue(center.getJSON(), forKey: "center")
        values.setValue(perimeterArray, forKey: "perimeter")

        return values

    }
}

let peri = [LatLng(latitude: 10.0, longitude: 10.0), LatLng(latitude: 20.0, longitude: 20.0)]
let center = LatLng(latitude: 15.0, longitude: 15.0)

let field = Field(name: "test", center: center, perimeter: peri)

let json = try NSJSONSerialization.dataWithJSONObject(field.getJSON(), options: .PrettyPrinted)
let jsonString = NSString(data: json, encoding: NSUTF8StringEncoding)
print(jsonString)

//PRINTS THE FOLLOWING OUTPUT
Optional({
    "name" : "test",
    "center" : {
        "longitude" : 15,
        "latitude" : 15
    },
    "perimeter" : [{
        "longitude" : 10,
        "latitude" : 10
    },
    {
        "longitude" : 20,
        "latitude" : 20
    }]
})

UPDATE

In order to serialise an array of Field objects, you can do something like this.

let field1 = Field(name: "value1", center: center, perimeter: peri)
let field2 = Field(name: "value2", center: center, perimeter: peri)
let field3 = Field(name: "value3", center: center, perimeter: peri)

let fieldArray = [field1.getJSON(), field2.getJSON(), field3.getJSON()]

let json = try NSJSONSerialization.dataWithJSONObject(fieldArray, options: .PrettyPrinted)
let jsonString = NSString(data: json, encoding: NSUTF8StringEncoding)

Please note that this is just a quick solution, not the best one. This is just to give you an idea of how it will go. I'm sure you'll be able to improve on it.

Malik
  • 3,763
  • 1
  • 22
  • 35
  • Thank you! Very nice and concise solution. This is the information I couldn't find (googling "Swift 3 json convert array of struct within struct" wasn't cutting it, and I didn't know of the relevant terms). – Busman Oct 05 '17 at 17:57
  • How would you suggest I serialize a whole array of Field objects? That's the last thing I need to know from my question. – Busman Oct 05 '17 at 18:33
  • Thanks for updating it for me! Yeah, I read a lot of stuff about how people handle JSON with Swift. It seems to change rapidly over time. I just came from Android where I was able to use Gson. Man that was convenient... – Busman Oct 06 '17 at 03:25
  • It's a lot more easier in Swift 4. I haven't worked in it much since my current projects are in Swift 2 & 3 and they are too huge to migrate over. But I would highly recommend checking Swift 4 out. It will make your life a lot easier. Especially in terms of JSON parsing. – Malik Oct 06 '17 at 06:21