ios - Swift-Extensiones de protocolo-Valores predeterminados de la propiedad
protocol-oriented (3)
Es por eso que no fue posible establecer las propiedades.
La propiedad se convierte en una propiedad calculada, lo que significa que no tiene una variable de respaldo como _x como lo haría en ObjC. En el código de la solución a continuación, puede ver que xTimesTwo no almacena nada, sino que simplemente calcula el resultado de x.
Ver Documentos oficiales en propiedades calculadas.
La funcionalidad que desea también puede ser Property Observers.
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
}
}
Puedes modificar otras propiedades dentro del setter / getters, que es para lo que están destinadas
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'' con el protocolo identificable en la estructura A y la estructura B. Pero imagine que si tuviera N más estructuras que deben ajustarse a este protocolo ... no quiero ''copiar / pegar'' ''la conformidad (var id: Int, var nombre: 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 Identificable sin tener que implementar ambas propiedades:
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, id y name solo son gettable. Ahora si cambio las propiedades de identificación y nombre a {get set} , aparece el siguiente error:
El tipo ''C'' no se ajusta al protocolo ''Identificable''
Este error ocurre porque no he implementado un setter en la extensión de protocolo ... Así que 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 establezco un nuevo valor para el id o name, obtiene el valor predeterminado (getter). Por supuesto, el colocador está vacío .
Mi pregunta es: ¿Qué parte del código tengo que poner dentro del setter? Porque si agrego self.id = newValue se bloquea (recursivo).
Gracias por adelantado.
Los protocolos y las extensiones de protocolo son muy potentes, pero tienden a ser más útiles para las funciones y propiedades de solo lectura.
para lo que estás tratando de lograr (propiedades almacenadas con un valor predeterminado), las clases y la herencia en realidad 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)")
Parece que desea agregar una stored property
a un tipo a través de la extensión de protocolo. Sin embargo, esto no es posible porque con las extensiones no puede agregar una propiedad almacenada.
Puedo mostrarte un par de alternativas.
Subclasificación (programación orientada a objetos)
La forma más fácil (como probablemente ya lo imagine) es usar clases 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 clase A debe heredar de
IdentifiableBase
y como en Swift no hay herencia múltiple, esta será la única clase A de la que podrá heredar.
Componentes (Programació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 se ajuste a Identifiable
simplemente escribiendo
struct A: Identifiable {
var identifiableComponent = IdentifiableComponent()
}
Prueba
var a = A()
a.name = "test"
print(a.name) // test