Xcode warning: Immutable property will not be decoded because it is declared with an initial value which cannot be overwritten

前端 未结 3 1632
我寻月下人不归
我寻月下人不归 2021-02-18 23:33

Running Xcode 12, my Swift 5 Xcode project now has warnings whenever a Decodable or Codable type declares a let constant with an initial v

3条回答
  •  自闭症患者
    2021-02-18 23:49

    This warning appears because immutable properties with initial values don't participate in decoding - after all, they're immutable and they have an initial value, which means that initial value will never be changed.

    For example, consider this code:

    struct Model: Decodable {
        let value: String = "1"
    }
    
    let json = """
    {"value": "2"}
    """
    let decoder = JSONDecoder()
    let model = try! decoder.decode(Model.self, from: json.data(using: .utf8)!)
    print(model)
    

    This will actually print Model(value: "1"), even though the json we gave it had value as "2".

    In fact, you don't even need to provide the value in the data you're decoding, since it has an initial value anyway!

    let json = """
    {}
    """
    let decoder = JSONDecoder()
    let model = try! decoder.decode(Model.self, from: json.data(using: .utf8)!)
    print(model) // prints "Model(value: "1")"
    

    Changing the value to a var means it will decode correctly:

    struct VarModel: Decodable {
        var value: String = "1"
    }
    let json = """
    {"value": "2"}
    """
    let varModel = try! decoder.decode(VarModel.self, from: json.data(using: .utf8)!)
    print(varModel) // "VarModel(value: "2")"
    

    If you're seeing this error, it means your code has never correctly parsed the property in question when decoding. If you change it to a var, the property will be parsed correctly, which might be what you want - however, you should make sure that the data you're decoding always has that key set. For example, this will throw an exception (and crash since we're using try!):

    let json = """
    {}
    """
    let decoder = JSONDecoder()
    
    struct VarModel: Decodable {
        var value: String = "1"
    }
    
    let varModel = try! decoder.decode(VarModel.self, from: json.data(using: .utf8)!)
    

    In conclusion, Xcode's suggestion is probably viable in many cases, but you should evaluate on a case by case basis whether changing the property to a var will break your app's functionality.

    If you want the property to always return the hard-coded initial value (which is what's happening right now), consider making it a computed property or a lazy var.

提交回复
热议问题