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

前端 未结 3 1611
我寻月下人不归
我寻月下人不归 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

    Noah's explanation is correct. It’s a common source of bugs and it's not immediately obvious what’s happening due to the “magical” behaviour of Codable synthesis, which is why I added this warning to the compiler, since it brings your attention to the fact that the property won't be decoded and makes you explicitly call it out if that's the expected behaviour.

    As the fix-it explains, you have a couple of options if you want to silence this warning - which one you choose depends on the exact behaviour you want:

    1. Pass the initial value via an init:
    struct ExampleItem: Decodable {
      let number: Int
        
      init(number: Int = 42) {
        self.number = number
      }
    }
    

    This will allow number to be decoded, but you can also pass around instances of ExampleItem where the default value is used.

    You can also use it directly inside init instead, during decoding:

    struct ExampleItem: Decodable {
      let number: Int
        
      private enum CodingKeys: String, CodingKey {
        case number
      }
        
      init(from decoder: Decoder) throws {
        let container = try decoder.container(keyedBy: CodingKeys.self)
        number = try container.decodeIfPresent(Int.self, forKey: .number) ?? 42
      }
    }
    

    This will allow number to be decoded, but use 42 as the default value if the decoding fails.

    1. Make the property a var, although you can also make it a private(set) var:
    struct ExampleItem: Decodable {
      var number: Int = 42
    }
    

    Making it a var will allow number to be decoded, but it will also allow callers to modify it. By marking it as private(set) var instead, you can disallow this if you want.

    1. Define an explicit CodingKeys enum:
    struct ExampleItem: Decodable {
      let number: Int = 42
      
      private enum CodingKeys: CodingKey {}
    }
    

    This will prevent number from being decoded. Since the enum has no cases, this makes it clear to the compiler that there are no properties that you want to decode.

提交回复
热议问题