swiftcodable

Codable default values during initialization


I am new to Swift and I am working on a feature flag concept for my project and I am stuck using codable for default flag values. Currently my code looks like this

import Foundation 

class KillSwitches: Codable {

    public enum CodingKeys: String, CodingKeys {
        case featureOne
        case featureTwo
        case featureThree
    }

    let featureOne: Bool = true
    let featureTwo: Bool = true
    let featureThree: Bool = false
}

I have internal helper classes which helps with encoding and decoding of all the values from the json file and that's why its not explicitly mentioned here. Prior to this implementation I didn't have any default values and was using struct reading everything from a remote config file which was working fine. Now I am in my next step to have default values for my features if in case the remote config file is unreachable.

I was expecting that I could initialize this class so I will get an object of the class with the default just like what I was getting when I read from my remote file.

I am not able to instantiate this class without passing init(from decoder:). I even tried doing

KillSwitches.init(from: KillSwitches.self) which is not working either and I get the Type does not conform to expected type Decoder.

My Json looks like this

{
  "featureOne" : false,
  "featureTwo" : true,
  "featureThree" : true
}

Any guidance / pointers to resolve this problem is much appreciated.


Solution

  • Once you conform to Encodable, it's as if your class has explicitly declared a encode(to:) method and a init(from:) initialiser.

    By declaring an initialiser with arguments, you immediately lose the default (parameterless) initialiser that the compiler generates for you when all properties have a default value. This is why you can't do KillSwitches(). This is stated in the documentation:

    Swift provides a default initializer for any structure or class that provides default values for all of its properties and does not provide at least one initializer itself. The default initializer simply creates a new instance with all of its properties set to their default values.

    KillSwitches has a init(from:) initialiser already, so Swift doesn't provide the default initialiser.

    You just have to add the parameterless initialiser in yourself:

    class KillSwitches: Codable {
    
        public enum CodingKeys: String, CodingKey {
            case featureOne
            case featureTwo
            case featureThree
        }
    
        let featureOne: Bool = true
        let featureTwo: Bool = true
        let featureThree: Bool = false
    
        init() { }
    }
    

    And then you can do:

    let defaultKillSwitches = KillSwitches()
    

    if you want the default values.