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:
- 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.
- Make the property a
var
, although you can also make it aprivate(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.
- 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:
Add
CodingKeys
and omit the keyid
private enum CodingKeys: String, CodingKey { case good, terrible }
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
Bitwise Operations with Cgbitmapinfo and Cgimagealphainfo
Executefetchrequest Doesn't Return the Nsmanagedobject Subclass
Difference Between Swift's Hash and Hashvalue
Class Level or Struct Level Method in Swift Like Static Method in Java
Error Using Associated Types and Generics
Avoid Consecutive "If Let" Declarations in Swift
Realitykit - Set Text Programmatically of an Entity of Reality Composer
Swiftui - Using Geometryreader Without Modifying the View Size
Synchronize Properties in Swift 3 Using Gcd
Swift, Pass Data Back from Popover to View Controller
How to Pass an Error Pointer in the Swift Language
Get a Unique String for a Given Anyobject
Convincing Swift That a Function Will Never Return, Due to a Thrown Exception
Vapor 3 Beta Example Endpoint Request
Nsurlsession/Nsurlconnection Http Load Failed (Kcfstreamerrordomainssl, -9802)
An Nsmanagedobject of Class 'Classname' Must Have a Valid Nsentitydescription.' Error
Xcode 9 - Test Target X Encountered an Error (Unable to Connect to Test Manager)