0

Situation

I'm trying to decode a simple JSON object of the form:

{
    "firstArray": [
        "element1",
        "element2"
    ],
    "secondArray": [
        "elementA",
        "elementB",
        "elementC"
    ],
    "*": [
        "bestElement"
    ] 
}

The result should be a custom object named ChainStore that contains an array of Chain instances. Each Chain holds an identifier and array of strings. See below.

I'd expect the array of chains in my ChainStore to be of the same order defined in the input JSON. For some reason, though, it gets the position of the special * chain wrong. All other elements stay in their defined position, so I'm pretty confident that it's not just ordered for some reason.

The actual result, if I just print the arrays, looks like this:

*
    bestElement
secondArray
    elementA
    elementB
    elementC
firstArray
    element1
    element2

I'm pretty sure I missed something in the documentation here.

Any idea why it doesn't respect my order or why it applies this seemingly random order?

Thanks!

Full example

var json = """
{
    "firstArray": [
        "element1",
        "element2"
    ],
    "secondArray": [
        "elementA",
        "elementB",
        "elementC"
    ],
    "*": [
        "bestElement"
    ]
}
""".data(using: .utf8)!

struct ChainService: Decodable {
    let chains: [Chain]

    struct ChainKey: CodingKey {
        var stringValue: String
        init?(stringValue: String) {
            self.stringValue = stringValue
        }
        var intValue: Int? { return nil }
        init?(intValue: Int) { return nil }
    }

    init(from decoder: Decoder) throws {
        let container = try decoder.container(keyedBy: ChainKey.self)

        var chains = [Chain]()
        for key in container.allKeys {
            let identifier = key.stringValue
            let elements = try container.decode([String].self, forKey: key)

            let chain = Chain(identifier: identifier, providers: elements)
            chains.append(chain)
        }

        self.chains = chains
    }
}

struct Chain {
    let identifier: String
    let providers: [String]
}

let decoder = JSONDecoder()
let chainStore = try decoder.decode(ChainService.self, from: json)

for chain in chainStore.chains {
    print(chain.identifier)

    for element in chain.providers {
        print("\t\(element)")
    }
}
flohei
  • 5,248
  • 10
  • 36
  • 61
  • 4
    I guess it's because Dictionary don't care about order. The access is set with key, not index. – Larme Apr 05 '18 at 09:30
  • Your input is the JSON representation of an object/hash/map/dictionary. The order of properties in all these data structures is not important. If you want to get the values in the same order they are listed in the JSON you have to put them into an array at the source (and encode the array as JSON). – axiac Apr 05 '18 at 09:32
  • Also see this: https://developer.apple.com/library/content/documentation/Swift/Conceptual/Swift_Programming_Language/ControlFlow.html#//apple_ref/doc/uid/TP40014097-CH9-ID121 "The contents of a Dictionary are inherently unordered, and iterating over them does not guarantee the order in which they will be retrieved. In particular, the order you insert items into a Dictionary doesn’t define the order they are iterated. For more about arrays and dictionaries, see Collection Types." – Larme Apr 05 '18 at 09:33
  • Thanks, everyone! I thought about this, but because I had a similar case where my order was seemingly maintained I wasn't so sure anymore. Thanks for clarifying! – flohei Apr 05 '18 at 09:47

0 Answers0