pourquoi puis-je le faire sans erreur:
var testDto = ModelDto(modelId: 1)
testDto.objectId = 2
alors que je définis ceci:
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 définition dans mon protocole est la plupart du temps ignorée (définition de getter, setter), pourquoi devrais-je les utiliser quand même?
Selon le documentation officielle :
Les exigences relatives au getter et au setter peuvent être satisfaites par un type conforme de différentes manières. Si une déclaration de propriété inclut à la fois les mots-clés get et set, un type conforme peut l'implémenter avec une propriété de variable stockée ou une propriété calculée, lisible et inscriptible (c'est-à-dire qui implémente à la fois un getter et un setter). Cependant, cette déclaration de propriété ne peut pas être implémentée en tant que propriété constante ou en tant que propriété calculée en lecture seule. Si une déclaration de propriété n'inclut que le mot clé get, elle peut être implémentée comme tout type de propriété.
Apple déclare dans le "Swift Programming Language (Swift 3)" :
Si le protocole requiert uniquement qu'une propriété soit getting, l'exigence peut être satisfaite par n'importe quel type de propriété. Cette propriété est également valide si elle est utile pour votre propre code.
Pour cette raison, les cinq extraits de code suivants de Playground sont tous valides:
Exemple n ° 1: propriété 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"
Exemple n ° 2: propriété de variable
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"
Exemple # 3: propriété calculée (get seulement)
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"
Exemple # 4: propriété calculée (get et 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"
Exemple n ° 5: private(set)
propriété de variable
/* 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 déclare également:
Si un protocole nécessite qu'une propriété soit paramétrable et définissable, cette propriété ne peut pas être remplie par une propriété stockée constante ou une propriété calculée en lecture seule.
Pour cette raison, les deux extraits de code de Playground suivants ARE NOT sont valides:
Exemple n ° 1: propriété 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'
Exemple # 2: propriété calculée (get seulement)
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'
Exemple # 3: propriété calculée (get seulement)
protocol FullyNamed {
var fullName: String { get }
}
struct Duck: FullyNamed {
var fullName: String {return "Scrooge McDuck"}
init(fullName: String) {
self.fullName = fullName
// Error Message Cannot assign to Property: "FullName" is get only
}
}
Dans votre classe, vous créez une propriété stockée nommée objectId
. Dans votre protocole, vous spécifiez que la propriété a besoin d'un getter - c'est sa seule exigence.
Si vous vouliez que ce soit une propriété d'ordinateur, comme vous vous y attendiez, vous devez déclarer objectId
avec les éléments suivants:
var objectId: Int{ return (someNumber) }
Sans la fermeture pour calculer la valeur, il s'agit par défaut d'une propriété stockée.
Je réponds à la question dans son sens générique.
Avant de répondre à la question, vous devez savoir ce que signifie get
& set
.
(Si vous venez d'un monde Objective-C :) get
signifie readOnly , c'est-à-dire que je suis autorisé à connaître le nombre de pattes d'un animal. Je ne suis pas autorisé à le définir. get
& set
ensemble signifie readWrite c’est-à-dire que j’ai le droit de connaître le poids d’un animal tout en étant également capable de le définir/de le modifier.
Avec l'exemple suivant.
protocol Animal {
var weight : Int { get set }
var limbs : Int { get }
}
private (set)
..., alors vous n'obtiendrez pas d'erreur. C'est probablement ce que vous vouliez et comment il faut le faire!Probablement ce que vous vouliez:
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
Probablement ce que vous n'aviez pas l'intention:
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
En gros, avec {get}
, il reste encore du travail extra que le compilateur ne vous dit pas ... VOUS devez ajouter private (set)
pour obtenir le comportement souhaité.
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'
}
Vous n'êtes pas autorisé à vous cacher, car vous avez promis de fournir un passeur ...
Le comportement que vous observez sur votre exemple de code s'appelle masquage de membre. La dissimulation de membre se produit dans les langages orientés objet lorsqu'un nouveau membre est déclaré avec le même nom ou la même signature qu'un membre hérité. var objectId: Int
dans votre implémentation de structure, vous créez effectivement un nouveau membre appelé objectId et masquez la propriété héritée du protocole.
Afin d'honorer le contrat entre votre structure et votre protocole, objectId pourrait être déclaré comme:
let objectId: Int = 1
ou
var objectId: Int {
get {
return 1
}
}