The backticks don't have any direct relevance to the error messages you're seeing. If xxx is a declared property name known to the compiler, then both of the following:
xxx
`xxx`
refer to that same property name. You only need the backticks when the compiler can't tell whether you mean the variable name or some Swift keyword.
If you wrote this, therefore:
`self` = try container.decode(URL.self, forKey: .`self`)
you'd be writing the same thing as:
self = try container.decode(URL.self, forKey: .`self`)
That is, the compiler thinks you're trying to replace the object of type Links with a different one. Since you're not allowed to do that in a designated initializer, the compiler gives an error. (You can replace self in a convenience initializer, but that's a different discussion.)
The compiler didn't know that you were trying to replace the self property of the self object. To do that, you must be explicit by saying it is the self property of the self object! You would expect to be able to write this as:
self.self = try container.decode(URL.self, forKey: .`self`)
However, for historical reasons, the compiler treats self.self as simply self, so that doesn't do what you want. To tell the compiler that you mean your self property, you have to disambiguate with more backticks:
self.`self` = try container.decode(URL.self, forKey: .`self`)
As Claude says, a less confusing option here would be to use a different property name instead of self. You can specify a different property name from the encoding key name, ending up with something a bit more readable:
class Links: ObservableObject, Codable {
@Published var myself: URL
required init(from decoder: Decoder) throws {
let container = try decoder.container(keyedBy: CodingKeys.self)
myself = try container.decode(URL.self, forKey: .myself)
}
private enum CodingKeys: String, CodingKey {
case myself = "self"
}
func encode(to encoder: Encoder) throws {
var container = encoder.container(keyedBy: CodingKeys.self)
try container.encode(myself, forKey: .myself)
}
}