1

I have an array of struct's that I need to write to a server side code, I can't seem to find any examples of adding a json object with multiple parent keys.

struct Photo {
    var imageName = "", thumbFileURL = "", viewCount = 0, likeCount = 0
}

and then I have a couple of photo object that are declared like...

var photo1 = Photo()
photo1.imageName = "ImPhoto1"
photo1.thumbFileURL = "www.SO.com"
photo1.viewCount = 5
photo1.likeCount = 1

var photo2 = Photo()
photo1.imageName = "ImPhoto2"
photo1.thumbFileURL = "www.SO.com"
photo1.viewCount = 10
photo1.likeCount = 2
////// and then same for x amount of Photo() object

And then I have an array

myArray = [photo1,photo2,photo3, ...]

and then I need to write a json that looks something ike this:

myJson object = {
    photo1: {
        imageName: "ImPhoto1"
        thumbFileURL = "www.SO.com"
        viewCount: 5
        likeCount: 1
    },
    photo2: {
        imageName: "Imphoto2"
        ....
    },
    ....
}

so my question is, how do I convert myarray -> myJson

3
  • let tempData = try? JSONEncoder().encode(myArray) //Create JSON var Finaldata: Any? if let data = tempData { finalData = try? JSONSerialization.jsonObject(with: data, options: .allowFragments) } Commented Mar 27, 2018 at 5:59
  • Fatal error: Array<Photo> does not conform to Encodable because Photo does not conform to Encodable.: Commented Mar 27, 2018 at 6:05
  • Nice! Almost, What would I do to add a parent key to the data then? like the "Photo1" and "Photo2" key? Commented Mar 27, 2018 at 6:12

2 Answers 2

2

You need a custom implementation of Encodable of PhotoCollection, which is a wrapper type for an array of photos:

struct Photo : Codable {
    var imageName = "", thumbFileURL = "", viewCount = 0, likeCount = 0
}

struct PhotoCollection: Encodable, ExpressibleByArrayLiteral {
    var photos: [Photo]

    typealias ArrayLiteralElement = Photo

    init(arrayLiteral elements: Photo...) {
        photos = elements
    }

    func encode(to encoder: Encoder) throws {
        var container = encoder.container(keyedBy: CodingKeys.self)
        for (i, photo) in photos.enumerated() {
            try container.encode(photo, forKey: CodingKeys(stringValue: "photo\(i + 1)")!)
        }
    }

    struct CodingKeys: CodingKey, ExpressibleByStringLiteral {
        var stringValue: String { return key }

        init?(stringValue: String) {
            key = stringValue
        }

        var intValue: Int? { return Int(key) }

        init?(intValue: Int) {
            key = "\(intValue)"
        }

        init(stringLiteral value: String) {
            key = value
        }

        var key: String
    }
}

var photo1 = Photo()
photo1.imageName = "ImPhoto1"
photo1.thumbFileURL = "www.SO.com"
photo1.viewCount = 5
photo1.likeCount = 1

var photo2 = Photo()
photo1.imageName = "ImPhoto2"
photo1.thumbFileURL = "www.SO.com"
photo1.viewCount = 10
photo1.likeCount = 2

let photoCollection: PhotoCollection = [photo1, photo2]
let json = try JSONEncoder().encode(photoCollection)
print(String(data: json, encoding: .utf8)!)

This prints:

{"photo2":{"imageName":"","likeCount":0,"viewCount":0,"thumbFileURL":""},"photo1":{"imageName":"ImPhoto2","likeCount":2,"viewCount":10,"thumbFileURL":"www.SO.com"}}

Formatted:

{
  "photo2": {
    "imageName": "",
    "likeCount": 0,
    "viewCount": 0,
    "thumbFileURL": ""
  },
  "photo1": {
    "imageName": "ImPhoto2",
    "likeCount": 2,
    "viewCount": 10,
    "thumbFileURL": "www.SO.com"
  }
}
Sign up to request clarification or add additional context in comments.

2 Comments

So if I already have an array of photos, How can I decode the array in to PhotoCollection? I can't seem to run the code: Photocollection: PhotoCollection = myarray..
@RyanB. You want to decode as well as encode? What does your json look like?
0
struct Photo:Codable {
    var imageName = "", thumbFileURL = "", viewCount = 0, likeCount = 0
}

var photo1 = Photo()
photo1.imageName = "ImPhoto1"
photo1.thumbFileURL = "www.SO.com"
photo1.viewCount = 5
photo1.likeCount = 1

var photo2 = Photo()
photo1.imageName = "ImPhoto2"
photo1.thumbFileURL = "www.SO.com"
photo1.viewCount = 10
photo1.likeCount = 2
var myArray = [photo1,photo2]
let tempData = try? JSONEncoder().encode(myArray)
//Create JSON
var Finaldata: Any?
if let data = tempData { Finaldata = try? JSONSerialization.jsonObject(with: data, options: .allowFragments) } 

This Will Work

2 Comments

Are you sure this is what the OP wanted? This creates a JSON array, but the OP wants a JSON object.
@Cristik Check The question op used the same value thats why

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.