Let's say that I have the following protocol:
protocol Identifiable {
var id: Int {get}
var name: String {get}
}
And that I have the following structs:
struct A: Identifiable {
var id: Int
var name: String
}
struct B: Identifiable {
var id: Int
var name: String
}
As you can see, I had to 'conform' to the Identifiable protocol in struct A and struct B. But imagine if I had N more structs that needs to conform to this protocol... I don't want to 'copy/paste' the conformance (var id: Int, var name: String)
So I create a protocol extension:
extension Identifiable {
var id: Int {
return 0
}
var name: String {
return "default"
}
}
With this extension now I can create a struct that conforms to the Identifiable protocol without having to implement both properties:
struct C: Identifiable {
}
Now the problem is that I can't set a value to the id property or the name property:
var c: C = C()
c.id = 12 // Cannot assign to property: 'id' is a get-only property
This happens because in the Identifiable protocol, id and name are only gettable. Now if I change the id and name properties to {get set} I get the following error:
Type 'C' does not conform to protocol 'Identifiable'
This error happens because I haven't implemented a setter in the protocol extension... So I change the protocol extension:
extension Identifiable {
var id: Int {
get {
return 0
}
set {
}
}
var name: String {
get {
return "default"
}
set {
}
}
}
Now the error goes away but if I set a new value to id or name, it gets the default value (getter). Of course, the setter is empty.
My question is: What piece of code do I have to put inside the setter? Because if I add self.id = newValue it crashes (recursive).
Thanks in advance.
It seems you want to add a stored property
to a type via protocol extension. However this is not possible because with extensions you cannot add a stored property.
I can show you a couple of alternatives.
The easiest way (as probably you already imagine) is using classes instead of structs.
class IdentifiableBase {
var id = 0
var name = "default"
}
class A: IdentifiableBase { }
let a = A()
a.name = "test"
print(a.name) // test
Cons: In this case your A class needs to inherit from
IdentifiableBase
and since in Swift theres is not multiple inheritance this will be the only class A will be able to inherit from.
This technique is pretty popular in game development
struct IdentifiableComponent {
var id = 0
var name = "default"
}
protocol HasIdentifiableComponent {
var identifiableComponent: IdentifiableComponent { get set }
}
protocol Identifiable: HasIdentifiableComponent { }
extension Identifiable {
var id: Int {
get { return identifiableComponent.id }
set { identifiableComponent.id = newValue }
}
var name: String {
get { return identifiableComponent.name }
set { identifiableComponent.name = newValue }
}
}
Now you can make your type conform to Identifiable
simply writing
struct A: Identifiable {
var identifiableComponent = IdentifiableComponent()
}
Test
var a = A()
a.identifiableComponent.name = "test"
print(a.identifiableComponent.name) // test