Projected Value
In diesem (voraussichtlich letzten) Teil zum Thema Property Wrapper in Swift 5.1 möchte ich euch ein weiteres kleines Feature vorstellen, das die Arbeit mit dieser neuen Technik abrundet.
Die Rede ist vom sogenannten Projected Value. Das erlaubt es, eine beliebige zusätzliche Information über einen Property Wrapper auszuliefern. Typ und damit Art dieser Information kann von euch vollkommen frei festgelegt werden. Dieses Projected Value wird innerhalb einer Property Wrapper-Implementierung über eine Property namens projectedValue
umgesetzt. Der Name ist entscheidend und muss immer zwingend projectedValue
lauten (vergleichbar der wrappedValue
-Property).
Ein Beispiel für die Umsetzung und Implementierung eines Projected Value findet ihr im folgenden Listing. Basis ist der SmallNumber
-Property Wrapper aus dem vorangegangenen Teil dieser Artikelserie. Der wird nun um eine passende projectedValue
-Property ergänzt, die in diesem Fall dem Typ Bool
entspricht (wie geschrieben könnt ihr diesen Typ pro Property Wrapper selbst frei bestimmen).
In dem gezeigten Beispiel dient das Projected Value als ergänzende Information beim Setzen eines Werts über den SmallNumber
-Property Wrapper. Es entspricht false
, wenn der zugewiesene Wert unterhalb des Maximums liegt und so der zugewiesene Wert wie gewünscht übernommen wird. Andernfalls – sprich wenn der neue Wert das definierte Maximum übersteigt und so jenes Maximum verwendet wird – wird das Projected Value auf true
gesetzt. So kann nach Zuweisung einer Zahl zu einer SmallNumber
-Instanz nachvollzogen werden, welche Art von Änderung durchgeführt wurde.
@propertyWrapper
struct SmallNumber {
private var maximum: Int
private var currentNumber: Int
var projectedValue = false
var wrappedValue: Int {
get {
return currentNumber
}
set {
if newValue <= maximum {
currentNumber = newValue
projectedValue = false
} else {
currentNumber = maximum
projectedValue = true
}
}
}
init(wrappedValue: Int, maximum: Int) {
self.maximum = maximum
currentNumber = min(wrappedValue, maximum)
}
}
Doch wie greift man nun auf jene Info zurück, die innerhalb des Projected Value und damit innerhalb der projectdValue
-Property von SmallNumber
gespeichert ist?
Basis hierfür ist das $
-Zeichen. Stellt man das einer Instanz voran, die konform zu einem Property Wrapper ist, greift man so statt auf den eigentlichen Wert der Instanz auf das Projected Value zu.
Ein Beispiel hierfür findet ihr im folgenden Listing. Darin wird erneut der SomeRectanlge
-Typ mit den beiden SmallNumber
-Properties height
und width
definiert. Anschließend erfolgt die Erstellung einer SomeRectangle
-Instanz und eine Änderung der beiden Properties.
Interessant hierbei: height
erhält mit 50
einen Wert, der unter dem Maximum von 100
liegt, weshalb height
auch erfolgreich der Wert 50
zugewiesen werden kann. width
hingegen erhält als Wert 100
, nachdem versucht wurde, einen Wert von 200
zuzuweisen (der aber eben das Maximum von 100
übersteigt). Das Projected Value entspricht demnach für die height
-Property false
und für die width
-Property true
.
Um jenes Ergebnis des Projected Value zu ermitteln, stellt man den Properties height
und width
schlicht ein $
-Zeichen voran. So erhält man statt des zugewiesenen Zahlenwerts die boolesche Information aus dem Projected Value (wie in den abschließenden print(_:)
-Aufrufen im Listing zu sehen).
struct SomeRectangle {
@SmallNumber(maximum: 100) public var height: Int = 10
@SmallNumber(maximum: 100) public var width: Int = 10
}
var someRectangle = SomeRectangle()
someRectangle.height = 50
someRectangle.width = 200
print("height: \(someRectangle.height)")
// height: 50
print("$height: \(someRectangle.$height)")
// $height: false
print("width: \(someRectangle.width)")
// widht: 100
print("$width: \(someRectangle.$width)")
// $widht: true
Übrigens: Verfügt ein Property Wrapper über kein Projected Value, verhindert der Compiler die Verwendung eines vorangestellten $
-Zeichens für zugehörige Properties (die würden schließlich dann ins Leere laufen). So müsst ihr euch keine Sorgen darüber machen, die $
-Syntax ohne Verfügbarkeit eines Projected Value einzusetzen; das ist dank des Compilers nicht möglich.
Fazit
Mithilfe eines Projected Value lässt sich ein Property Wrapper um eine beliebige zusätzliche Information ergänzen. Das macht zwar nicht für jeden Property Wrapper Sinn, kann aber im Fall der Fälle sehr hilfreich sein, um mehr über die Funktionsweise eines Property Wrapper an eine zugehörige Property weiterzugeben.
Euer Thomas
Schreibe einen Kommentar