Swift: extensiones de protocolo: valores pnetworkingeterminados de la propiedad

Digamos que tengo el siguiente protocolo:

protocol Identifiable { var id: Int {get} var name: String {get} } 

Y que tengo las siguientes estructuras:

 struct A: Identifiable { var id: Int var name: String } struct B: Identifiable { var id: Int var name: String } 

Como puede ver, tuve que "conformarme" al protocolo identificable en la estructura A y la estructura B. Pero imagínese si tuviera N más estructuras que deban ajustarse a este protocolo … No quiero copyr / pegar 'la conformidad (var id: Int, var name: String)

Entonces creo una extensión de protocolo :

 extension Identifiable { var id: Int { return 0 } var name: String { return "default" } } 

Con esta extensión ahora puedo crear una estructura que se ajuste al protocolo de identificación sin tener que implementar ambas properties:

 struct C: Identifiable { } 

Ahora el problema es que no puedo establecer un valor para la propiedad id o la propiedad name:

 var c: C = C() c.id = 12 // Cannot assign to property: 'id' is a get-only property 

Esto sucede porque en el protocolo identificable, la identificación y el nombre solo se pueden get. Ahora, si cambio las properties de identificación y nombre para {get set} , obtendré el siguiente error:

Tipo 'C' no se ajusta al protocolo 'Identificable'

Este error ocurre porque no implementé un setter en la extensión del protocolo … Entonces cambio la extensión del protocolo:

 extension Identifiable { var id: Int { get { return 0 } set { } } var name: String { get { return "default" } set { } } } 

Ahora el error desaparece, pero si configuro un nuevo valor para id o nombre, obtendrá el valor pnetworkingeterminado (getter). Por supuesto, el setter está vacío .

Mi pregunta es: ¿Qué código debo poner en el setter? Porque si agrego self.id = newValue se bloquea (recursivo).

Gracias por adelantado.

Parece que desea agregar una stonetworking property a un tipo a través de la extensión del protocolo. Sin embargo, esto no es posible porque con las extensiones no puede agregar una propiedad almacenada.

Puedo mostrarte un par de alternativas.

Subsorting (Progtwigción Orientada a Objetos)

La forma más fácil (como probablemente ya se imagina) es usar classs en lugar de estructuras.

 class IdentifiableBase { var id = 0 var name = "default" } class A: IdentifiableBase { } let a = A() a.name = "test" print(a.name) // test 

Contras: en este caso, su class A debe henetworkingar de IdentifiableBase y dado que en Swift theres no es una inheritance múltiple, esta será la única class A que podrá henetworkingar.

Componentes (Progtwigción orientada a protocolo)

Esta técnica es bastante popular en el desarrollo de juegos.

 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 } } } 

Ahora puede hacer que su tipo sea conforme a Identifiable simplemente escribiendo

 struct A: Identifiable { var identifiableComponent = IdentifiableComponent() } 

Prueba

 var a = A() a.name = "test" print(a.name) // test 

Los protocolos y las extensiones de protocolo son muy potentes, pero tienden a ser más útiles para properties y funciones de solo lectura.

por lo que está tratando de lograr (properties almacenadas con un valor pnetworkingeterminado), las classs y la inheritance podrían ser la solución más elegante

algo como:

 class Identifiable { var id: Int = 0 var name: String = "default" } class A:Identifiable { } class B:Identifiable { } let a = A() print("\(a.id) \(a.name)") a.id = 42 a.name = "foo" print("\(a.id) \(a.name)") 

Es por eso que no pudiste configurar las properties.

La propiedad se convierte en una propiedad computada, lo que significa que no tiene una variable de respaldo como _x como lo haría en ObjC. En el siguiente código de solución, puede ver que xTimesTwo no almacena nada, sino que simplemente calcula el resultado de x.

Consulte Documentos oficiales en properties computadas.

La funcionalidad que desee también podría ser Observadores de propiedad.

Setters / getters son diferentes de lo que eran en Objective-C.

Lo que necesitas es:

 var x:Int var xTimesTwo:Int { set { x = newValue / 2 } get { return x * 2 } } 

Puede modificar otras properties dentro del setter / getters, que es para lo que están destinadas