¿El protocolo Swift solo se puede configurar?
¿Por qué puedo hacer esto sin ningún error:
var testDto = ModelDto(modelId: 1)
testDto.objectId = 2
Mientras defino esto:
protocol DataTransferObject {
var objectType: DtoType { get }
var parentObjectId: Int { get set }
var objectId: Int { get }
var objectName: String { get set }
}
struct ModelDto: DataTransferObject {
var objectType: DtoType
var parentObjectId: Int
var objectId: Int
var objectName: String
init(modelId: Int) {
self.objectType = DtoType.Model
self.objectId = modelId
self.parentObjectId = -1
self.objectName = String()
}
}
Si la definición en mi protocolo es ignorada en su mayoría (definición getter, setter), ¿por qué debería usarlos de todos modos?
6 answers
Según la documentación oficial :
Los requisitos de getter y setter pueden ser satisfechos por un tipo conforme en una variedad de maneras. Si una declaración de propiedad incluye las palabras clave get y set, un tipo conforme puede implementarla con una propiedad variable almacenada o una propiedad computada que sea legible y escribible (es decir, una que implemente tanto un getter como un setter). Sin embargo, esa declaración de propiedad no se puede implementar como una propiedad constante o un propiedad calculada de solo lectura. Si una declaración de propiedad solo incluye la palabra clave get, se puede implementar como cualquier tipo de propiedad.
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2017-03-02 21:10:03
Apple indica en el " Lenguaje de programación Swift (Swift 3)":
Si el protocolo solo requiere que una propiedad sea gettable, el requisito puede ser satisfecho por cualquier tipo de propiedad, y es válido que la propiedad también sea settable si esto es útil para su propio código.
Por esta razón, los cinco siguientes fragmentos de código de Playground son todos válidos:
Ejemplo # 1: propiedad constante
protocol FullyNamed {
var fullName: String { get }
}
struct Duck: FullyNamed {
let fullName: String
}
let scrooge = Duck(fullName: "Scrooge McDuck")
print(scrooge.fullName) // returns "Scrooge McDuck"
Ejemplo # 2: variable propiedad
protocol FullyNamed {
var fullName: String { get }
}
struct Duck: FullyNamed {
var fullName: String
}
var scrooge = Duck(fullName: "Scrooge McDuck")
print(scrooge.fullName) // returns "Scrooge McDuck"
scrooge.fullName = "Scrooge H. McDuck"
print(scrooge.fullName) // returns "Scrooge H. McDuck"
Ejemplo # 3: propiedad computada (get only)
protocol FullyNamed {
var fullName: String { get }
}
struct Duck: FullyNamed {
private var name: String
var fullName: String {
return name
}
}
let scrooge = Duck(name: "Scrooge McDuck")
print(scrooge.fullName) // returns "Scrooge McDuck"
Ejemplo # 4: propiedad calculada (get y set)
protocol FullyNamed {
var fullName: String { get }
}
struct Duck: FullyNamed {
private var name: String
var fullName: String {
get {
return name
}
set {
name = newValue
}
}
}
var scrooge = Duck(name: "Scrooge McDuck")
print(scrooge.fullName) // returns "Scrooge McDuck"
scrooge.fullName = "Scrooge H. McDuck"
print(scrooge.fullName) // returns "Scrooge H. McDuck"
Ejemplo # 5: private(set)
variable property
/* Duck.swift located in Sources folder */
protocol FullyNamed {
var fullName: String { get }
}
public struct Duck: FullyNamed {
public private(set) var fullName: String
public init(fullName: String) {
self.fullName = fullName
}
public mutating func renameWith(fullName: String) {
self.fullName = fullName
}
}
/* Playground file */
var scrooge = Duck(fullName: "Scrooge McDuck")
print(scrooge.fullName) // returns "Scrooge McDuck"
scrooge.renameWith("Scrooge H. McDuck")
print(scrooge.fullName) // returns "Scrooge H. McDuck"
Apple también afirma:
Si un protocolo requiere que una propiedad sea gettable y settable, ese requisito de propiedad no se puede cumplir con una propiedad almacenada constante o una propiedad calculada de solo lectura.
Para esto razón, los dos siguientes fragmentos de código de Playground NO SON válidos:
Ejemplo # 1: propiedad constante
protocol FullyNamed {
var fullName: String { get set }
}
struct Duck: FullyNamed {
let fullName: String
}
let scrooge = Duck(fullName: "Scrooge McDuck")
// Error message: Type 'Duck' does not conform to protocol 'FullyNamed'
Ejemplo # 2: propiedad computada (get only)
protocol FullyNamed {
var fullName: String { get set }
}
struct Duck: FullyNamed {
private var name: String
var fullName: String {
return name
}
}
var scrooge = Duck(name: "Scrooge McDuck")
// Error message: Type 'Duck' does not conform to protocol 'FullyNamed'
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2016-07-13 12:57:23
Considere lo siguiente:
var testDto = ModelDto(modelId: 1)
El tipo de variable testDto
aquí se sabe que es ModelDto
. ModelDto
se sabe que tiene una variable mutable var objectId: Int
. Eres libre de modificar ObjectId porque tienes acceso al objeto a través de la interfaz ModelDto
y no a través de la interfaz de protocolo donde solo es gettable.
Intente lo siguiente:
var testDto: DataTransferObject = ModelDto(modelId: 1)
testDto.objectId = 2 // compiler error
El ejemplo anterior no debería compilar. Debido a que el tipo de testDto
solo se sabe que es DataTransferObject
, no sabemos que el subyacente la implementación tiene una propiedad configurable. Solo conocemos la propiedad gettable declarada en el protocolo.
En resumen, has declarado que ModelDto
tiene una variable get/set, por lo que sería bastante extraño si Swift no te dejara configurarla. Tener una variable get solo dependería de que usted refiera el objeto a través del protocolo o cambie objectId
en ModelDTO
para que sea una variable let.
EDITAR: Para resolver su confusión acerca de por qué se permite a ModelDto
tener una variable configurable. Es lo mismo que cómo se permite a ModelDto
tener otras funciones que las definidas en el protocolo. Los getters y setters son en realidad solo funciones, por lo que el protocolo que requiere un getter no impide que una implementación también tenga un setter. Lo mismo es posible en Objective C. Los protocolos son descriptivos, no restrictivos.
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2016-07-09 12:35:44
En su clase, crea una propiedad almacenada llamada objectId
. En su protocolo, usted especifica que la propiedad necesita un getter-ese es su único requisito.
Si quieres que sea una propiedad de la computadora, como esperas que sea, necesitas declarar objectId
con lo siguiente:
var objectId: Int{ return (someNumber) }
Sin el cierre para calcular el valor, es, por defecto, una propiedad almacenada.
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2015-06-01 12:49:52
El comportamiento que está viendo en su ejemplo de código se llama ocultamiento de miembros. La ocultación de miembros ocurre en lenguajes orientados a objetos cuando se declara un nuevo miembro con el mismo nombre o firma de uno heredado, por lo que al tener:
var objectId: Int
en su implementación de estructura, está creando efectivamente un nuevo miembro llamado ObjectId y ocultando la propiedad heredada del protocolo.
Para cumplir el contrato entre su estructura y su protocolo, ObjectId podría ser declarado as:
let objectId: Int = 1
O
var objectId: Int {
get {
return 1
}
}
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2015-11-06 23:37:15
Estoy respondiendo la pregunta en su sentido genérico.
Antes de abordar la pregunta, debe saber qué hace get
& set
cruel.
(Si vienes de un mundo Objective-C:) get
significa Readyonly, es decir, se me permite saber el número de patas que tiene un animal. No se me permite configurarlo. get
& set
juntos significa ReadWrite es decir, se me permite saber el peso de un animal, mientras que también soy capaz de establecer / cambiar el peso de un animal
Con el siguiente ejemplo.
protocol Animal {
var weight : Int { get set }
var limbs : Int { get }
}
Si solo tiene getter, e intenta ocultar setter (usando private (set)
... entonces NO obtendrá un error ... es probable que lo que quería y cómo se debe hacer!
Probablemente lo que pretendías:
class Cat : Animal {
private (set) var limbs: Int = 4 // This is what you intended, because you only have get requirements...and don't want any conforming type to be able to set it ie don't want others do catInstance.limbs = 22
var weight: Int = 15
}
var smallCat = Cat()
smallCat.weight = 20 // Good!
// attempting to set it will create an error!!!
smallCat.limbs = 5 // Error: Cannot assign to property: 'limbs' setter is inaccessible
Probablemente lo que no pretendías:
class Panda : Animal {
var limbs: Int = 4 // This is OK, but it kinda defeats the purpose of it being a get only
var weight: Int = 200
}
var littlPanda = Panda()
littlPanda.weight = 40 // Good
littlPanda.limbs = 30 // NO Error!!! Likely unintended
, Básicamente, con {get}
todavía hay algunos extra trabajo para hacer que el compilador no decirle ... USTED debe agregar private (set)
para lograr el comportamiento pretendido
Si su propiedad tiene setter e intenta ocultar setter, verá un error.
class Dog : Animal {
private (set) var limbs: Int = 4
private (set) var weight: Int = 50 // Error: Setter for property 'weight' must be declared internal because it matches a requirement in internal protocol 'Animal'
}
No se te permite esconderte, porque prometiste proporcionar un armador...
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2017-05-29 18:52:31