1

I have valid, working code, but I want to find out if there is a way to make it simpler and smaller.

I have a custom class Response which can be initialised from Json or text (depends on response from server)

public class Response: Codable {

let responseP1: String?
let responseP2: String?
let responseP3: String?

enum CodingKeys: String, CodingKey {
    case responseP1 = "someResponseCode1"
    case responseP2 = "someResponseCode2"
    case responseP3 = "someResponseCode3"
}

required init(_ response: [String: String]) {
    self.responseP1 = response["someResponseCode1"]
    self.responseP3 = response["someResponseCode2"]
    self.responseP2 = response["someResponseCode3"]
}

required public init(from decoder: Decoder) throws {
    let container = try decoder.container(keyedBy: CodingKeys.self)
    self.responseP1 = try container.decode(String.self, forKey: .responseP2)
    self.responseP3 = try container.decode(String.self, forKey: .responseP1)
    self.responseP2 = try container.decode(String.self, forKey: .responseP3)
}
}

can I combine Coding keys and initialisation with Dictionary somehow?

e.g. self.responseP1 = response[.responseP1] but self.responseP1 = response[CodingKeys.responseP1.rawValue] is working but looks like I am winning nothing in this case

Also I need to parse it all to String, but

public func encodeAsString() -> String? {
    do {
        let encodedResponse = try self.encoded()
        return String(decoding: encodedResponse, as: UTF8.self)
    } catch {
        return nil
    }
}

does not work for me (returns "{}" even when was initialised from Json not Text), can you give advise why?

Joakim Danielson
  • 43,251
  • 5
  • 22
  • 52
busido
  • 13
  • 5
  • 1
    You might find this a bit too convoluted, but [you can convert the dictionary into JSON, then decode the JSON](https://stackoverflow.com/a/53874532/5133585). – Sweeper Sep 02 '22 at 12:04
  • The last code snippet seems to be made up of calls to custom code so it's impossible to say why it doesn't work but shouldn't you do `String(data: try! JSONEncoder().encode(self), encoding: .utf8)` instead but with much better error handling of course ;) – Joakim Danielson Sep 02 '22 at 12:29
  • What does "Json or text" mean in this context? JSON is text. Do you have examples of the two payloads you want to decode? – Rob Napier Sep 02 '22 at 15:08
  • @Sweeper answered in Edit – busido Sep 02 '22 at 16:16
  • @JoakimDanielson answered in edit – busido Sep 02 '22 at 16:17
  • @RobNapier answered in Edit – busido Sep 02 '22 at 16:17
  • @JoakimDanielson had no space for an answer, will know for future – busido Sep 02 '22 at 16:33
  • I have rolled back your question to its original content since the edits are only confusing. If you have another question then post it as a new separate question – Joakim Danielson Sep 02 '22 at 16:36
  • Does this help [How can I make a Decodable object from a dictionary?](https://stackoverflow.com/questions/53873400/how-can-i-make-a-decodable-object-from-a-dictionary) – Cristik Sep 02 '22 at 16:52

1 Answers1

0

If your goal is just to be able to write self.responseP1 = response[.responseP1], then you need to convert the Dictionary to the right type [CodingKeys: String].

private static func convertKeys(from response: [String: String]) -> [CodingKeys: String] {
    Dictionary(uniqueKeysWithValues: response.compactMap {
        guard let key = CodingKeys.init(stringValue: $0) else { return nil }
        return (key: key, value: $1)
    })
}

required init(_ response: [String: String]) {
    let response = Self.convertKeys(from: response)
    self.responseP1 = response[.responseP1]
    self.responseP3 = response[.responseP2]
    self.responseP2 = response[.responseP3]
}
Rob Napier
  • 286,113
  • 34
  • 456
  • 610
  • 1
    looks great, thanks, now I am looking at @Sweeper suggestion and trying to completely remove initialisation via dictionary, but this answers my original Q – busido Sep 02 '22 at 16:19