2

I have this Struct:

struct Alphabet {
    let a = "ciao"
    let b = "hi"
    let c = "hola"
}

let alphabet = Alphabet()

I want the value of each property become the string of the property itself. Like this:

alphabet.a = "a"
alphabet.b = "b"
alphabet.c = "c"

But I want to be done regardless of the number of properties or their value:

I tried this:

Mirror(reflecting: Alphabet.self).children.forEach { (label, value) in
    self.alphabet[keyPath: label] = label!
}

but I know this is not the way KeyPath works... Probably there are type safety problems going on too. Any idea?

Dávid Pásztor
  • 51,403
  • 9
  • 85
  • 116
Lorenzo Fiamingo
  • 3,251
  • 2
  • 17
  • 35
  • Can you explain why an String enum wouldn't be appropriate to your case? Because that is pretty much what you need unless you give us more details about why do you have to use a struct. – Don Jan 07 '20 at 15:02
  • I'm mirroring Firestore Database – Lorenzo Fiamingo Jan 07 '20 at 15:21
  • And by 'become the string of the property' you mean you want to change a keypath to the value? Because by the your example I gathered you want the value to become the keyPath, but you wrote you want the string to become same as value. – Don Jan 07 '20 at 15:42
  • no, I want to change the property value, and the value should be the "property": let property = "property" – Lorenzo Fiamingo Jan 07 '20 at 15:46
  • Now I found that instead of struct I can use NSObject that has set value:forKey: , but I would prefer to use struct... – Lorenzo Fiamingo Jan 07 '20 at 15:47
  • Check my answer, If I understood you correctly this is the solution you need. – Don Jan 07 '20 at 16:03

1 Answers1

2

As far as I know keyPaths aren't the way to go, you need to use CodingKeys

Here's a working sample, creating JSON and then decoding it might not be the perfect so you better change my solution to suit your needs.



struct Alphabet: Codable {
    let a: String
    let b: String
    let c: String
    enum CodingKeys: String, CodingKey, CaseIterable
    {
        case a
        case b
        case c
    }

    static func generateJSON() -> String {
        var json = "{"
        for i in CodingKeys.allCases
        {
            json += "\"\(i.stringValue)\": \"\(i.stringValue)\","
        }
        json.removeLast()
        json += "}"
        return json
    }
}

let decoder = JSONDecoder()
let alphabet = try decoder.decode(Alphabet.self, from: Alphabet.generateJSON().data(using: .utf8)!)
print(alphabet.a) //Prints "a"

Don
  • 490
  • 3
  • 9
  • 1
    Why are you manually creating the JSON String inside `generateJSON`? Just use a `JSONEncoder`. – Dávid Pásztor Jan 07 '20 at 16:38
  • Umm, how would I pass CodingKeys stringValues to a JSONEncoder? It looks a little hacky, but was the easiest I could think of. – Don Jan 07 '20 at 17:09