Xcode Warning: Immutable Property Will Not Be Decoded Because It Is Declared with an Initial Value Which Cannot Be Overwritten

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

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.

Creating an Identifiable id gives inmutable warning

Either declare id as var or add CodingKeys and omit id.

And please name structs and classes always with starting capital letter

struct MyModel: Decodable, Identifiable {
private enum CodingKeys: String, CodingKey { case a, b, c }

let id = UUID()
let a, b, c: String
}

Add ID Property on Struct Fetched From JSON

use let id = UUID() instead of var id = UUID(), and the id will not be decoded.

If the Xcode warning scare you too much, you can also use this:

struct Recipe: Identifiable, Decodable {
let id = UUID()
let name:String
let featured:Bool
let image:String
let description:String
let prepTime:String
let cookTime:String
let totalTime:String
let servings:Int
let ingredients:[String]
let directions:[String]

// not including id
enum CodingKeys: String, CodingKey {
case name, featured, image, description, prepTime, cookTime
case totalTime, servings, ingredients, directions
}
}

SwiftUI: Receiving an error when decoding JSON

You are going to decode a key which is not part of the JSON.

There are two options:

  1. Add CodingKeys and omit the key id

    private enum CodingKeys: String, CodingKey { case good, terrible }
  2. Declare the member in the struct as constant, in this case the compiler skips all members with a default value

    let id = UUID()

    however you get a warning:

    immutable property will not be decoded because it is declared with an initial value which cannot be overwritten


Your last example with id : Int does work.

Basically you should declare all decoded struct members as constants which are immutable.

How to silence a warning in Swift?

As of 2021, Xcode 13.0, the consensus is that there is no way to achieve that.

I'll update/edit this answer if Apple add the feature.

Put it in your wish list for WWDC 2022 !

Attempting to store to property '' within its own willSet

This is a known bug, reported in the Apple Developer Forum: https://devforums.apple.com/message/1065306#1065306, with the workaround
of adding an explicit self:

    willSet {
self.someProperty?.someFunction()
}

Update: I could not reproduce the issue with Xcode 7.3.1 or Xcode 8
anymore, so that seems to be fixed now.

Cannot assign to property: Enum:case is not settable

Using an enum for this seems inappropriate, but I'll address the porblem at face value. You need to mark your setter as nonmutating, so that it can be called on non-var instances of your enum:

public enum CXActionSheetToolBarButtonItem {

// ...

public var title: String {
get { return CXActionSheetToolBarButtonItem.titles[self] ?? String(describing: self) }
nonmutating set(value) { CXActionSheetToolBarButtonItem.titles[self] = value }
}
}

CXActionSheetToolBarButtonItem.cancel.title = "foo" // Works... but why would you want this?!


Related Topics



Leave a reply



Submit