4

How can I call didSet method using Codable protocol.

    class Sample: Codable{
        var text : String? {
            didSet {
                print("didSet") // do not call
                extended_text = "***" + text! + "***"
            }
        }
        var extended_text : String?
    }

    let sample_json = "{\"text\":\"sample text\"}"
    let decoder = JSONDecoder()
    let sample = try! decoder.decode(Sample.self, from: sample_json.data(using: .utf8)!)
    print(sample.text!)
    print(sample.extended_text ?? "") 
Leo Dabus
  • 229,809
  • 59
  • 489
  • 571
Maiko Ohkawa
  • 853
  • 2
  • 11
  • 28

1 Answers1

4

Instead of using didSet you should just make extendedText a read only computed property. Note that it is Swift convention to use camelCase instead of snake_case when naming your properties:

struct Sample: Codable {
    let text: String
    var extendedText: String {
        return "***" + text + "***"
    }
}

let sampleJson = """
{"text":"sample text"}
"""

do {
    let sample = try JSONDecoder().decode(Sample.self, from: Data(sampleJson.utf8))
    print(sample.text)            // "sample text\n"
    print(sample.extendedText)    // "***sample text***\n"
} catch {
    print(error)
}

An alternative if your goal is to run a method when initializing your Codable struct is to write your own custom decoder:

class Sample: Codable {
    let text: String
    required init(from decoder: Decoder) throws {
        let container = try decoder.singleValueContainer()
        text = try container.decode(String.self)
        print("did set")
    }
}

let sampleJson = "{\"text\":\"sample text\"}"
let decoder = JSONDecoder()
do {
    let sample = try decoder.decode([String: Sample].self, from: Data(sampleJson.utf8))
    print(sample["text"]?.text ?? "")
} catch {
    print(error)
}

This will print:

did set

sample text

Community
  • 1
  • 1
Leo Dabus
  • 229,809
  • 59
  • 489
  • 571
  • Thank you. You're correct. However, my code is sample. Actually processing is more complex and I think I need to retain converted object. I'm sorry I didn't make it clear enough. – Maiko Ohkawa Dec 21 '17 at 02:25
  • Thank you. I fixed representation misleading. – Maiko Ohkawa Dec 21 '17 at 02:31
  • 3
    @MaikoOhkawa note that this has nothing to do with `Codable` protocol. if you set the text property `sample.text = "any text"` it will call `didSet` but not when initializing your `class` or `struct` – Leo Dabus Dec 21 '17 at 02:32
  • I didn't know "but not when initializing your class or struct". I see. My question cleared up. I will consider another processing. Thank you a lot. – Maiko Ohkawa Dec 21 '17 at 02:40
  • @MaikoOhkawa What you can do is create a custom decoder initializer and execute whatever you need there. – Leo Dabus Dec 21 '17 at 02:56