Programmazione rapida: getter / setter nella proprietà memorizzata


102

Come faccio a sovrascrivere il setter della proprietà memorizzata in Swift?

In Obj-C, posso sovrascrivere il suo setter, ma Swift non sembra essere contento che getter / setter vengano usati per la proprietà memorizzata.

Supponiamo che io abbia una Cardclasse con una proprietà chiamata rank. Non voglio che il client gli dia alcun valore non valido, quindi, in Object-C, posso sovrascriverlo in setRankmodo che esegua un controllo aggiuntivo. Ma willSetin Swift non sembra aiutare perché newValueè costante e non ha senso assegnare rankperché il setter verrà chiamato in un ciclo.


Hai trovato un modo per farlo? Ho bisogno di questo tipo di funzionalità io stesso ...
Mihai Fratu

L'ho trovato. Controlla la mia risposta ...
Mihai Fratu

Che mi dici di didGet o analogico?
fnc12

Risposte:


107

Ok. Leggendo la documentazione di Apple su Swift ho trovato questo :

Se si assegna un valore a una proprietà all'interno del proprio osservatore didSet, il nuovo valore che si assegna sostituirà quello appena impostato.

Quindi tutto ciò che devi fare è questo:

var rank: Int = 0 {
    didSet {
        // Say 1000 is not good for you and 999 is the maximum you want to be stored there
        if rank >= 1000  {
            rank = 999
        }
    }
}

Che mi dici di didGet o analogico?
fnc12

Non sono sicuro di aver capito la tua domanda. Puoi essere più specifico, per favore?
Mihai Fratu

Devo richiamare del codice prima di ottenere. Sono stato in grado di eseguire questo in obj-c ma non riesco a vedere come farlo in Swift. L'unica cosa che vedo è usare due proprietà: una è pubblica e una è privata, public invoca il mio codice e restituisce il valore della proprietà privata. Questo è il motivo per cui ho chiesto informazioni su didGet
fnc12

Puoi avere solo un getter per una proprietà calcolata. Ad esempiovar rankTimesTwo: Int { get { return rank * 2 } }
Mihai Fratu

2
Funziona come un fascino! Attenzione che non verrà chiamato quando si imposta la proprietà in init ()
Christoph

35

Non è possibile sovrascrivere get/ setper una proprietà memorizzata ma è possibile utilizzare osservatori di proprietà willSet/ didSet:

var totalSteps: Int = 0 {
    willSet(newTotalSteps) {
        println("About to set totalSteps to \(newTotalSteps)")
    }
    didSet {
        if totalSteps > oldValue  {
            println("Added \(totalSteps - oldValue) steps")
        }
    }
}

I nomi dei parametri predefiniti sono newValueper willSete oldValueper didSet, oppure puoi nominarli tu stesso come in willSet(newTotalSteps).


Funziona. Ma non risolve il mio problema, forse non ero abbastanza chiaro nella mia domanda iniziale.
bohanl

Supponiamo che io abbia una Cardclasse con una proprietà chiamata rank. Non voglio che il client gli dia alcun valore, quindi, in Object-C, posso sovrascrivere in setRankmodo che esegua un controllo aggiuntivo. Ma willSetin Swift non sembra aiutare perché newValueè costante e non ha senso assegnare rankperché il setter verrà chiamato in un ciclo.
bohanl

2
Non sono del tutto sicuro di cosa intendi ma non potresti usarlo didSetper controllare rankdopo che è stato impostato e se fallisce la convalida, ripristinalo su qualcos'altro, ad esempio oldValue?
Joseph Mark

9

get e set sono per proprietà calcolate (non hanno alcun archivio di backup). (A mio parere, la parola chiave "var" è fonte di confusione qui)

  • willSet e didSet sono chiamati per una variabile di istanza (usa didSet per sovrascrivere qualsiasi modifica)
  • set e get sono puramente per proprietà calcolate

9

Se non si desidera utilizzare didSet, che presenta il problema che il valore della proprietà è temporaneamente errato, è necessario racchiudere una proprietà calcolata attorno ad esso.

private var _foo:Int = 0
var foo:Int {
    get {
        return _foo
    }
    set {
        if(newValue > 999) {
            _foo = 999
        } else {
            _foo = newValue
        }
    }
}

O:

private var _foo:Int = 0
var foo:Int {
    get {
        return _foo
    }
    set {
        guard newValue <= 999 else {
            _foo = 999
            return
        }
        _foo = newValue
    }
}

Non ha senso usare due variabili.
Piyush

1
Questo utilizza solo una proprietà (variabile): fooè solo un'espressione calcolata di _foo, non lasciarti ingannare dalla parola chiave "var"! Significa che ci sono due voci accessibili dallo spazio dei nomi privato, ma ciò non ha alcuna relazione con protected / public e mantiene il valore di foovalido in ogni momento. Questo è essenzialmente il modello di "visualizzazione". Il problema che si verifica con la riscrittura tramite didSet, oltre ad avere un periodo di non validità, è che esiste un potenziale significativo per un ciclo infinito poiché si sta rientrando nel didSetgestore dall'interno didSet.
Jim Driscoll

-8

Esempio semplificato:

class Shape {
    var sideLength: Double {
    get {
        return self.sideLength
    }
    set {
        // Implement the setter here.
        self.sideLength = newValue
    }
    }
}

Esempio completo

Check-out perimeter in questo esempio.

Estratto da: Apple Inc. "The Swift Programming Language". iBook. https://itun.es/us/jEUH0.l

class EquilateralTriangle: NamedShape {
    var sideLength: Double = 0.0

    init(sideLength: Double, name: String) {
        self.sideLength = sideLength
        super.init(name: name)
        numberOfSides = 3
    }

    var perimeter: Double {
    get {
        return 3.0 * sideLength
    }
    set {
        sideLength = newValue / 3.0
    }
    }

    override func simpleDescription() -> String {
        return "An equilateral triagle with sides of length \(sideLength)."
    }
}
var triangle = EquilateralTriangle(sideLength: 3.1, name: "a triangle")
triangle.perimeter
triangle.perimeter = 9.9
triangle.sideLength”

3
in questo caso, perimeterè ancora una proprietà calcolata. Come si sovrascrive sideLength senza introdurre una proprietà calcolata?
bohanl

@bohanl ho aggiunto un esempio semplificato usando geteset
Mike Rapadas

6
Il tuo "esempio completo" mostra una proprietà calcolata, non una proprietà memorizzata, e il tuo "esempio semplificato" non funziona.
Caleb

Mi correggo. È come se l'astrazione di @property (getter + setter auto-sintetizzati) in Objective-C non fosse stata astratta in Swift. L'ironia ...
Mike Rapadas

6
Il tuo "esempio semplificato" sta chiamando un getter all'interno di un getter di se stesso. Ciclo inf ... crash.
jakenberg
Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.