J'ai réfléchi à la manière d'utiliser correctement WillSet de Swift.

Premier article pour les débutants avec 3 mois d'histoire Swift

Tout en étudiant Swift par vous-même, vous utiliserez le résultat pour étoffer les connaissances que vous avez apprises. C'est la première fois que vous sortez, et cela sert également de pratique de sortie.

La tâche que j'ai faite cette fois

Apprenez en remodelant une classe de carrés avec une longueur Int de chaque côté.

Objectif

Pouvoir utiliser les connaissances acquises en les codant sous une forme proche de la pratique.

-À propos de l'utilité de ** willSet ** et ** didSet ** --Utilisation de ** Propriété en lecture seule ** à l'aide des propriétés de calcul --Résolution des violations du principe DRY

Condition: quel genre de carré?

--Dispose de propriétés de hauteur et de largeur de type Int

Code initial

class IntBox{
    enum Size{
        case S, M, L
    }

    //Hauteur horizontale et verticale
    var width: Int
    var height: Int
    var depth: Int

    //le volume
    var volume: Int

    //Taille
    var size:Size
    
    init(w: Int, h: Int, d: Int){
	//Initialisation de la hauteur horizontale et verticale
        width = w
        height = h
        depth = d
	
	//Initialisation du volume
        volume = w * h * d
	
	//Initialisation de la taille
        switch volume{
        case 1...8:
            size = .S
        case 9...64:
            size = .M
        default:
            size = .L
        }
    }

    //Une fonction pour afficher la liste des statuts est fournie pour vérification.
    func printStatus(){
        var status = """
        ---statut---
        width: \(width)
        height: \(height)
        depth: \(depth)
        volume: \(volume)
        size: \(size)
        """
        print(status)
    }
}

Où plonger

  1. La condition de maximum 6 de chaque côté est ignorée.
  2. Aucune erreur ne se produit lorsque la longueur d'un côté est égale ou inférieure à 0.
  3. Le volume et la taille ne changent pas même si la longueur du côté est modifiée.
  4. Le volume peut être modifié de l'extérieur.
  5. La taille peut être modifiée de l'extérieur.

Vérification

let cb = IntBox(w: 1, h: 1, d: 1)
cb.printStatus()

//Essayez de changer la largeur
cb.width = 11
cb.printStatus()

//Essayez de changer le volume
cb.volume = -20
cb.printStatus()

//Essayez de changer la taille
cb.size = .L
cb.printStatus()

Résultat d'exécution

---statut---
width: 1
height: 1
depth: 1
volume: 1
size: S

---statut---
width: 11
height: 1
depth: 1
volume: 1 #Devraient changer!!
size: S

---statut---
width: 11
height: 1
depth: 1
volume: -20 #Il est étrange que 0 ou moins ne puisse pas être défini(Le volume dépend de la longueur de chaque côté)
size: S

---statut---
width: 11
height: 1
depth: 1
volume: -20
size: L #Il est étrange qu'il puisse être réglé ainsi que le volume. Pensez aux dépendances

Je vais donc le résoudre un par un.

# 1 Validation

[Pushing point](#Pushing point) 1 et 2 sont résolus.

1 La condition d'un maximum de 6 de chaque côté est ignorée.

2 Aucune erreur ne se produit lorsque la longueur d'un côté est égale ou inférieure à 0.

Insérez ce qui suit au début de l'initialisation.

if w <= 0 || w > 6 {fatalError("w:\(w) not in 1...6")}
if h <= 0 || h > 6 {fatalError("h:\(h) not in 1...6")}
if d <= 0 || d > 6 {fatalError("d:\(d) not in 1...6")}

# 2 willSet et didSet

Résoudre [Pousser](# Pousser) 3.

Le volume et la taille ne changent pas même si la longueur des trois côtés est modifiée.

Parce que je veux changer le volume et la taille lorsque les valeurs de hauteur et de largeur changent Ajoutez ** willSet ** et ** didSet ** à chaque propriété et définissez-y le volume et la taille.

fera quoi faire à quel moment

La validation signifie la vérification que vous pouvez définir la longueur que vous souhaitez modifier, donc avant de la définir. Après le réglage, le volume et la taille changeront en raison du changement de longueur.

--willSet: Validation --detSet: jeu de volume et de taille

var width: Int{
    willSet{
        if newValue<= 0 || newValue> 6 {fatalError("<width: \(newValue)> not in 1...6")}
    }
    didSet{
        _volume = width * height * depth
        switch _volume{
        case 1...8:
            _size = .S
        case 9...64:
            _size = .M
        default:
            _size = .L
        }
    }
}

var height: Int{
    willSet{
        if newValue<= 0 || newValue> 6 {fatalError("<height: \(newValue)> not in 1...6")}
    }
    didSet{
        _volume = width * height * depth
        switch _volume{
        case 1...8:
            _size = .S
        case 9...64:
            _size = .M
        default:
            _size = .L
        }
    }
}

var depth: Int{
    willSet{
        if newValue<= 0 || newValue> 6 {fatalError("<depth: \(newValue)> not in 1...6")}
    }
    didSet{
        _volume = width * height * depth
        switch _volume{
        case 1...8:
            _size = .S
        case 9...64:
            _size = .M
        default:
            _size = .L
        }
    }
}

# 3 Propriété en lecture seule.

[Pushing point](#Pushing point) Résout 4 et 5.

4 Le volume peut être modifié de l'extérieur. 5 La taille peut être modifiée de l'extérieur.

Le définir sur Propriété en lecture seule rend impossible la définition.

private var _volume: Int
private var _size: Size

var volume: Int {
    get {
        return _volume
    }
}

var size: Size {
    get {
        return _size
    }
}

Une fois complété! ??

.. .. .. Le code est aussi redondant que vous pouvez l'imaginer.

class IntBox{
    enum Size{
        case S, M, L
    }
    private var _volume: Int
    private var _size: Size

    var width: Int{
        willSet{
            if newValue<= 0 || newValue> 6 {fatalError("<width: \(newValue)> not in 1...6")}
        }
        didSet{
            _volume = width * height * depth
        switch _volume{
            case 1...8:
                _size = .S
            case 9...64:
                _size = .M
            default:
                _size = .L
            }
        }
    }
    
    var height: Int{
        willSet{
            if newValue<= 0 || newValue> 6 {fatalError("<height: \(newValue)> not in 1...6")}
        }
        didSet{
            _volume = width * height * depth
        switch _volume{
            case 1...8:
                _size = .S
            case 9...64:
                _size = .M
            default:
                _size = .L
            }
        }
    }
    
    var depth: Int{
        willSet{
            if newValue<= 0 || newValue> 6 {fatalError("<depth: \(newValue)> not in 1...6")}
        }
        didSet{
            _volume = width * height * depth
        switch _volume{
            case 1...8:
                _size = .S
            case 9...64:
                _size = .M
            default:
                _size = .L
            }
        }
    }
    
    var volume: Int {
        get {
    	    return _volume
        }
    }
    
    var size: Size {
        get {
    	    return _size
        }
    }
    
    init(w: Int, h: Int, d: Int){
        if w <= 0 || w > 6 {fatalError("<w: \(w)> not in 1...6")}
        if h <= 0 || h > 6 {fatalError("<h: \(h)> not in 1...6")}
        if d <= 0 || d > 6 {fatalError("<d: \(d)> not in 1...6")}
        width = w
        height = h
        depth = d
        _volume = w * h * d
        switch _volume{
        case 1...8:
            _size = .S
        case 9..<64:
            _size = .M
        default:
            _size = .L
        }
    }
    
    func printStatus(){
        var status = """
        ---statut---
        width: \(width)
        height: \(height)
        depth: \(depth)
        volume: \(volume)
        size: \(size)
        """
        print(status)
    }
}

let cb = IntBox(w: 1, h: 1, d: 1)
cb.printStatus()

//Essayez de changer la largeur
cb.width = 11
cb.printStatus()

Puisqu'il y a de nombreuses violations du principe DRY, je vais créer une fonction commune et la mettre ensemble.

# 4 Principe DRY appliqué

La partie validation doit être regroupée dans une fonction

private func lengthValidate(_ length: Int, _ name: String = "length"){
    if length <= 0 || length > 6 { fatalError("<\(name): \(length)> not in 1...6") }
}

Résumer les calculs de volume et les évaluations de taille

private func setStatus() {
    setVolume()
    setSize()
}

private func setVolume() {
    _volume = width * height * depth
}

private func setSize(){
    switch _volume{
        case 1...8:
            _size = .S
        case 9...64:
            _size = .M
        default:
            _size = .L
    }
}

Je veux aussi éliminer le fait que *** setStatus () *** est appelé chaque fois que je change la hauteur et la largeur.

Ce serait bien si ** setStatus () ** pouvait être créé lorsque le volume ou la taille est référencé. Cependant, il n'y a pas de changement Je veux également éviter d'appeler ** setStatus () ** chaque fois que le volume ou la taille est référencé. Je veux appeler ** setStatus () ** une seule fois après avoir changé la hauteur et la largeur. ** private var shouldSetStatus: crée un Bool ** et évalue s'il faut appeler ** setStatus () **.

private var shouldSetStatus: Bool

var width: Int = 1 {
    willSet { lengthValidate(newValue, "width") }
    didSet { shouldSetStatus = true } // <-Changement
}
...

var volume: Int {
    get {
        if shouldSetStatus { setStatus() }
        return _volume
    }
}
...

private func setStatus() {
    setVolume()
    setSize()
    shouldSetStatus = false // <-ajouter à
}

Code après résolution de la violation du principe DRY

class IntBox{
    enum Size{
        case S, M, L
    }
    
    private var _volume: Int = 1
    private var _size: Size = .S
    private var shouldSetStatus: Bool = false
    
    var width: Int = 1 {
        willSet { lengthValidate(newValue, "width") }
        didSet { shouldSetStatus = true }
    }
    var height: Int = 1 {
        willSet { lengthValidate(newValue, "height") }
        didSet { shouldSetStatus = true }
    }
    var depth: Int = 1 {
        willSet { lengthValidate(newValue, "depth") }
        didSet { shouldSetStatus = true }
    }

    var volume: Int {
        get {
            if shouldSetStatus { setStatus() }
            return _volume
        }
    }
    var size: Size {
        get {
            if shouldSetStatus { setStatus() }
    	    return _size
        }
    }
    
    init(w: Int, h: Int, d: Int){
        lengthValidate(w, "w")
        lengthValidate(h, "h")
        lengthValidate(d, "d")
        width = w
        height = h
        depth = d
        setStatus()
    }
    
    private func lengthValidate(_ length: Int, _ name: String = "length"){
    	if length <= 0 || length > 6 { fatalError("<\(name): \(length)> not in 1...6") }
    }
    
    private func setStatus() {
        setVolume()
        setSize()
        shouldSetStatus = false
    }
    
    private func setVolume() {
        _volume = width * height * depth
    }
    
    private func setSize(){
        switch _volume{
            case 1...8:
                _size = .S
            case 9...64:
                _size = .M
            default:
                _size = .L
        }
    }
    
    //Code de vérification
    func printStatus(){
        let status = """
        ---statut---
        width: \(width)
        height: \(height)
        depth: \(depth)
        volume: \(volume)
        size: \(size)
        """
        print(status)
    }
}

//Vérification
let cb = IntBox(w: 1, h: 2, d: 3)
cb.printStatus()

//Essayez de changer la largeur
cb.width = 5
cb.printStatus()

finalement

À l'origine, il a été conçu à partir d'un protocole abstrait afin que la valeur maximale d'un côté et l'évaluation de S, M, L puissent être modifiées de manière flexible. Concernant l'erreur, il ne s'agit que de ** fatalError ** sans utiliser ** Optional **, mais il vaut mieux renvoyer ** nil ** au moment de l'initialisation ou le séparer de l'erreur au moment du changement de longueur. Cela peut être bon. .. .. Une fois, j'ai écrit un article sur mes meilleurs efforts actuels. Un jour, je grandirai au point où cela semble être un article embarrassant. J'ai également passé 2 heures x 3 jours sur cet article. .. .. J'écrirai un article avec cospa à l'esprit.

Recommended Posts

J'ai réfléchi à la manière d'utiliser correctement WillSet de Swift.
J'étais curieux de savoir comment utiliser correctement Optional orElse () et orElseGet ().
À propos de la question pour laquelle j'étais accro à l'utilisation de hashmap
Comment configurer et utiliser kapt
J'ai réfléchi à la façon de le rendre sans serveur tout en évitant le verrouillage des fournisseurs
Comment utiliser le mémo personnel codable de Swift
Comment utiliser Map
Comment utiliser rbenv
Comment utiliser with_option
Comment utiliser fields_for
Comment utiliser java.util.logging
Comment utiliser Maven que je n'entends plus
Comment utiliser la carte
Comment utiliser collection_select
Comprendre comment utiliser le décodeur JSON de Swift en 3 minutes
[Rails] Je ne sais pas comment utiliser le modèle ...
Comment utiliser Twitter4J
Comment utiliser active_hash! !!
Comment utiliser MapStruct
Comment utiliser TreeSet
[Comment utiliser l'étiquette]
Comment utiliser l'identité
Comment utiliser le hachage
Comment utiliser Dozer.mapper
Comment utiliser Gradle
Comment utiliser org.immutables
Comment utiliser java.util.stream.Collector
Comment utiliser VisualVM
Comment utiliser Map
Une histoire de malentendu sur l'utilisation du scanner Java (mémo)
Comment utiliser l'API Chain
[Java] Comment utiliser Map
Comment utiliser Queue avec priorité
[Rails] Comment utiliser enum
Comment utiliser java Facultatif
Comment utiliser JUnit (débutant)
Comment utiliser le retour Ruby
[Rails] Comment utiliser enum
Comment utiliser @Builder (Lombok)
Comment utiliser la classe Java
Comment utiliser Big Decimal
[Java] Comment utiliser removeAll ()
Comment définir nginx de Docker
Comment utiliser String [] args
Comment utiliser la jonction de rails
Comment utiliser Java Map
Comment définir des constantes Java
Ruby: Comment utiliser les cookies
Comment utiliser Dependant :: Destroy
Comment utiliser Eclipse Debug_Shell
Comment utiliser Apache POI
[Swift] J'ai pensé à comparer
[Rails] Comment utiliser la validation