Ich dachte darüber nach, wie ich Swifts willSet richtig einsetzen sollte.

Erster Beitrag für Anfänger mit 3 Monaten Swift-Geschichte

Während Sie Swift alleine studieren, werden Sie die Ausgabe verwenden, um das erlernte Wissen zu verfeinern. Es ist das erste Mal, dass es sich selbst ausgibt, und es dient auch als Ausgabepraxis.

Die Aufgabe, die ich diesmal gemacht habe

Lernen Sie, während Sie eine Klasse von Quadraten mit Int-Länge auf jeder Seite umgestalten.

Zweck

In der Lage sein, das erlernte Wissen zu nutzen, indem man es in einer praxisnahen Form codiert.

-Über die Nützlichkeit von ** willSet ** und ** didSet **

Bedingung: Was für ein Quadrat?

Anfangscode

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

    //Horizontale und vertikale Höhe
    var width: Int
    var height: Int
    var depth: Int

    //Volumen
    var volume: Int

    //Größe
    var size:Size
    
    init(w: Int, h: Int, d: Int){
	//Initialisierung der horizontalen und vertikalen Höhe
        width = w
        height = h
        depth = d
	
	//Volumeninitialisierung
        volume = w * h * d
	
	//Größeninitialisierung
        switch volume{
        case 1...8:
            size = .S
        case 9...64:
            size = .M
        default:
            size = .L
        }
    }

    //Wir bieten eine Funktion zum Anzeigen der Statusliste zur Überprüfung.
    func printStatus(){
        var status = """
        ---Status---
        width: \(width)
        height: \(height)
        depth: \(depth)
        volume: \(volume)
        size: \(size)
        """
        print(status)
    }
}

Wo man eintaucht

  1. Die Bedingung von maximal 6 auf jeder Seite wird ignoriert.
  2. Es tritt kein Fehler auf, wenn die Länge einer Seite 0 oder weniger beträgt.
  3. Das Volumen und die Größe ändern sich nicht, auch wenn die Länge der Seite geändert wird.
  4. Die Lautstärke kann von außen geändert werden.
  5. Die Größe kann von außen geändert werden.

Überprüfung

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

//Versuchen Sie, die Breite zu ändern
cb.width = 11
cb.printStatus()

//Versuchen Sie, die Lautstärke zu ändern
cb.volume = -20
cb.printStatus()

//Versuchen Sie, die Größe zu ändern
cb.size = .L
cb.printStatus()

Ausführungsergebnis

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

---Status---
width: 11
height: 1
depth: 1
volume: 1 #Sollte wechseln!!
size: S

---Status---
width: 11
height: 1
depth: 1
volume: -20 #Es ist seltsam, dass 0 oder weniger nicht eingestellt werden kann(Das Volumen hängt von der Länge jeder Seite ab)
size: S

---Status---
width: 11
height: 1
depth: 1
volume: -20
size: L #Es ist seltsam, dass es ebenso wie die Lautstärke eingestellt werden kann. Denken Sie an Abhängigkeiten

Also werde ich es eins nach dem anderen lösen.

# 1 Validierung

[Druckpunkt](# Druckpunkt) 1 und 2 sind gelöst.

1 Die Bedingung von maximal 6 auf einer Seite wird ignoriert.

2 Wenn die Länge einer Seite 0 oder weniger beträgt, tritt kein Fehler auf.

Fügen Sie zu Beginn der Initialisierung Folgendes ein.

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 und didSet

Lösen Sie Drücken 3.

Volumen und Größe ändern sich auch dann nicht, wenn die Länge der drei Seiten geändert wird.

Weil ich das Volumen und die Größe ändern möchte, wenn sich die Werte für Höhe und Breite ändern Fügen Sie jeder Eigenschaft ** willSet ** und ** didSet ** hinzu und legen Sie dort das Volumen und die Größe fest.

wird getan, was zu welchem Zeitpunkt zu tun ist

Validierung bedeutet die Überprüfung, ob Sie die Länge festlegen können, die Sie ändern möchten, bevor Sie sie festlegen. Nach dem Einstellen ändern sich Volumen und Größe aufgrund der Längenänderung.

--willSet: Validierung --detSet: Lautstärke und Größe eingestellt

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 Schreibgeschützte Eigenschaft.

[Druckpunkt](# Druckpunkt) Löst 4 und 5.

4 Die Lautstärke kann von außen geändert werden. 5 Die Größe kann von außen geändert werden.

Das Festlegen der Eigenschaft "Schreibgeschützt" macht das Festlegen unmöglich.

private var _volume: Int
private var _size: Size

var volume: Int {
    get {
        return _volume
    }
}

var size: Size {
    get {
        return _size
    }
}

Einmal vervollständigt! ??

.. .. .. Der Code ist so redundant, wie Sie sich vorstellen können.

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 = """
        ---Status---
        width: \(width)
        height: \(height)
        depth: \(depth)
        volume: \(volume)
        size: \(size)
        """
        print(status)
    }
}

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

//Versuchen Sie, die Breite zu ändern
cb.width = 11
cb.printStatus()

Da es viele Verstöße gegen das DRY-Prinzip gibt, werde ich eine gemeinsame Funktion erstellen und zusammenstellen.

# 4 DRY-Prinzip angewendet

Der Validierungsteil sollte in einer Funktion zusammengefasst werden

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

Fassen Sie Volumenberechnungen und Größenbewertungen zusammen

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
    }
}

Ich möchte auch die Tatsache beseitigen, dass *** setStatus () *** jedes Mal aufgerufen wird, wenn ich die Höhe und Breite ändere.

Es wäre schön, wenn ** setStatus () ** erstellt werden könnte, wenn auf Volume oder Größe verwiesen wird. Es gibt jedoch keine Änderung Ich möchte auch vermeiden, ** setStatus () ** jedes Mal aufzurufen, wenn auf Volume oder Größe verwiesen wird. Ich möchte ** setStatus () ** nur einmal aufrufen, nachdem ich Höhe und Breite geändert habe. ** private var shouldSetStatus: Erstellt einen Bool ** und wertet aus, ob ** setStatus () ** aufgerufen werden soll.

private var shouldSetStatus: Bool

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

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

private func setStatus() {
    setVolume()
    setSize()
    shouldSetStatus = false // <-hinzufügen
}

Code nach Behebung des Verstoßes gegen das DRY-Prinzip

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
        }
    }
    
    //Verifizierungs-Schlüssel
    func printStatus(){
        let status = """
        ---Status---
        width: \(width)
        height: \(height)
        depth: \(depth)
        volume: \(volume)
        size: \(size)
        """
        print(status)
    }
}

//Überprüfung
let cb = IntBox(w: 1, h: 2, d: 3)
cb.printStatus()

//Versuchen Sie, die Breite zu ändern
cb.width = 5
cb.printStatus()

Schließlich

Ursprünglich wurde es aus einem abstrakten Protokoll entworfen, so dass der Maximalwert einer Seite und die Bewertung von S, M, L flexibel geändert werden konnten. In Bezug auf den Fehler ist es nur ** fatalError ** ohne Verwendung von ** Optional **, aber es ist besser, ** nil ** zum Zeitpunkt der Initialisierung zurückzugeben oder ihn zum Zeitpunkt der Längenänderung vom Fehler zu trennen. Es kann gut sein. .. .. Ich habe einmal einen Artikel über meine derzeitigen Bemühungen geschrieben. Eines Tages werde ich bis zu einem Punkt wachsen, an dem dies wie ein peinlicher Artikel erscheint. Ich habe auch 2 Stunden x 3 Tage mit diesem Artikel verbracht. .. .. Ich werde einen Artikel mit Blick auf Cospa schreiben.

Recommended Posts

Ich dachte darüber nach, wie ich Swifts willSet richtig einsetzen sollte.
Ich war neugierig, wie man Optional orElse () und orElseGet () richtig verwendet.
Über die Sache, dass ich süchtig danach war, wie man Hashmap benutzt
So richten Sie kapt ein und verwenden es
Ich überlegte, wie ich es serverlos machen und gleichzeitig die Lieferantenbindung vermeiden könnte
Verwendung von Swifts Codable Super Personal Memo
Verwendung von Map
Wie benutzt man rbenv?
Verwendung mit_option
Verwendung von fields_for
Verwendung von java.util.logging
Wie man Maven benutzt, das ich nicht mehr hören kann
Verwendung der Karte
Verwendung von collection_select
Verstehen Sie, wie Sie den JSON-Decoder von Swift in 3 Minuten verwenden
[Rails] Ich weiß nicht, wie ich das Modell verwenden soll ...
Wie benutzt man Twitter4J
Wie benutzt man active_hash! !!
Verwendung von MapStruct
Verwendung von TreeSet
[Verwendung des Etiketts]
Wie man Identität benutzt
Wie man Hash benutzt
Verwendung von Dozer.mapper
Wie benutzt man Gradle?
Verwendung von org.immutables
Verwendung von java.util.stream.Collector
Verwendung von VisualVM
Verwendung von Map
Eine Geschichte über Missverständnisse im Umgang mit Java-Scannern (Memo)
Verwendung der Ketten-API
[Java] Verwendung von Map
Verwendung der Warteschlange mit Priorität
[Rails] Verwendung von Enum
Verwendung von Java Optional
Verwendung von JUnit (Anfänger)
Verwendung von Ruby return
[Rails] Verwendung von Enum
Verwendung von @Builder (Lombok)
Verwendung der Java-Klasse
Wie man Big Decimal benutzt
[Java] Verwendung von removeAll ()
So legen Sie Nginx von Docker fest
Verwendung von String [] args
Verwendung von Rails Join
Verwendung von Java Map
So legen Sie Java-Konstanten fest
Ruby: Wie man Cookies benutzt
Verwendung von abhängigen :: zerstören
Verwendung von Eclipse Debug_Shell
Verwendung von Apache POI
[Swift] Ich dachte über Vergleiche nach
[Rails] Verwendung der Validierung