web-dev-qa-db-fra.com

Comment se conformer au set & get des variables d'un protocole?

Je joue avec les protocoles et comment m'y conformer.

protocol Human {    
    var height: Int {get set}    
}

struct boy : Human { 
    var height: Int  {return 5} // error!
}

J'essaie d'apprendre différentes façons d'implémenter set et get. Cependant, le code ci-dessus renvoie l'erreur suivante:

le type 'garçon' n'est pas conforme au protocole 'Humain'

Cependant, écrire comme ci-dessous n'aura aucune erreur:

struct boy : Human { 
    var height = 5 // no error
}

Je ne comprends pas la différence ni ce qui doit être implémenté exactement quand vous pouvez aussi set une variable. J'ai examiné différentes questions et tutoriels, mais ils écrivent et partent sans explication plus approfondie.

EDIT: assurez-vous de voir la réponse d'Imanou ici . Il explique grandement les différents scénarios.

11
Honey

À partir de Swift Reference :

Exigences de propriété

...
Le protocole ne spécifie pas si la propriété doit être une propriété stockée ou une propriété calculée, il spécifie uniquement le nom et le type de propriété requis.
...
Les exigences de propriété sont toujours déclarées comme propriétés de variable, précédées du mot clé var. Les propriétés getting et settable sont indiquées en écrivant { get set } après leur déclaration de type, et les propriétés getting sont indiquées en écrivant { get }.

Dans ton cas

var height: Int  {return 5} // error!

est une propriété calculée qui ne peut être que get, c'est un raccourci pour

var height: Int {
    get {
        return 5
    }
}

Mais le protocole Human nécessite une propriété qui est gettable et réglable. Vous pouvez soit vous conformer à une propriété variable stockée (comme vous l'avez remarqué):

struct Boy: Human { 
    var height = 5
}

ou avec une propriété calculée qui a à la fois getter et setter:

struct Boy: Human { 
    var height: Int {
        get {
            return 5
        }
        set(newValue) {
            // ... do whatever is appropriate ...
        }
    }
}
29
Martin R

Prérequis:

Allez dans votre terrain de jeu et écrivez simplement l'extrait ci-dessous:

var height: Int {
    get {
        return 5
    }
}    

ou similaire:

var height: Int {
    return 5
}    

Essayez d'imprimer la valeur de height, ça marche évidemment. Jusqu'ici tout va bien

print(height) // prints 5

Cependant, si vous essayez de définir une nouvelle valeur, vous obtiendrez une erreur:

height = 8 // ERROR  

erreur: impossible d'attribuer à la valeur: 'hauteur' est une propriété à lecture seule


Répondre:

Sur la base de la réponse de Martin, j'ai d'abord écrit:

set(newValue) {
    height = newValue 
}

Ce qui a mis une tonne de charge sur ma mémoire et m'a conduit à cette question. S'il vous plaît, jetez un oeil. Alors je me demandais quoi écrire, et j'ai compris que si vous ne voulez rien faire de spécial, vous ne devriez pas utiliser propriétés calculées et à la place, vous devez simplement utiliser les propriétés stockées normales.

J'ai donc écrit un code similaire

protocol Human {

    var height: Float {get set}

}

struct Boy: Human {

    // inch
    var USheight : Float

    // cm
    var height: Float {
        get {
            return 2.54 * USheight
        }
        set(newValue) {
         USheight = newValue/2.54

        }
    }
}

// 5 ft person
var person = Boy(USheight: 60)
 // interestingly the initializer is 'only' based on stored properties because they
 // initialize computed properties. 


// equals to 152cm person
print(person.height) // 152.4

Conseil de pro: quand devriez-vous mettre vos propriétés en lecture seule?

Normalement, si vous définissez une propriété en lecture seule, c'est-à-dire { get } c'est parce que ces propriétés sont calculées et que vous ne voulez pas que l'objet ait le contrôle dessus.

Exemple, vous avez un objet JSON. Il a plusieurs gros objets comme:

JSONData
 - userInfo (name, address, age)
 - devices (iPads, iPhones, Mac books)
 - credentials (basic iCloud, pro iCloud, celebrity)

en faisant du rôle une lecture seule, vous autorisez uniquement le serveur à indiquer à la base de code le rôle de l'utilisateur.

protocol Credentials {
    var role: String { get }

    init(person: Person)
}

class Person {
    var userInfo: String
    var devices: [String]
    var creds: Credentials {
        Credentials(person: self)
    }

    init(userInfo: userInfo, devices: [String]) {
        self.userInfo = userInfo
        self.devices = devices
    }
}
7
Honey