[Swift] PropertyWrapper 手を動かして理解する(その1 wrappedValue)
Sponsor Link
初期値指定
propertyWrapper 指定された property の初期値設定について説明します。
property wrapper init 内
property wrapper の init で設定することができます。
@propertyWrapper struct NoWrapInt {
init() {
self.wrappedValue = 0 // (1)
}
var wrappedValue: Int
}
struct CheckNoWrapInt {
@NoWrapInt var value:Int //(2)
}
var checkNoWrapInt = CheckNoWrapInt() // (3)
print(checkNoWrapInt.value) //(4)
(3)の struct が生成されるタイミングで、(1) の init が呼ばれ、初期値が設定されます。(4)で設定された初期値が、0 と表示されます。
ただ、この方法では、property wrapper を定義した箇所でのみ初期値を設定できることになります。少し不便です。
propertywrapper 修飾された 変数に初期値指定
通常の property と同様に、以下のように設定することができると直感的です。
@NoWrapInt var variable:Int = 5
このようなコードでは、propertywrapper の init(wrappedValue:Int) が呼びされます。
# 定義がないとエラーになります。
早速追加して実行してみます。
@propertyWrapper struct NoWrapInt {
init(wrappedValue: Int) {
self.wrappedValue = wrappedValue // (1)
}
var wrappedValue: Int
}
struct CheckNoWrapInt {
@NoWrapInt var value:Int = 4 // (2)
}
var checkNoWrapInt = CheckNoWrapInt()
print(checkNoWrapInt.value) // (3)
(1) で渡された値を設定する initializer を定義します。
(2) が実行されるときに、initializer が呼び出され設定されますので、(3) では、4 と表示されます。
property wrapper の初期化指定
Property wrapper に対して直接的に初期値を指定することもできます。
例えば上記の例では、以下のように記述することで、wrappedValue の初期値を指定することができます。
struct CheckNoWrapInt {
@NoWrapInt var value1:Int = 5 // (1)
@NoWrap(wrappedValue: 5) var value2:Int // (2)
}
(1), (2) とも同じ動作をします。init(wrappedValue:Int) を呼び出しています。
もう少し凝った初期値指定
もう少し凝った初期値指定もできますが、現在の NoWrapInt では、シンプルすぎるので、もう少し複雑な property wrapper を定義します。
property wrapper “WrapIntLowerLimit”
特定の値より小さい値をセットできない property wrapper を定義します。
@propertyWrapper struct WrapIntLowerLimit {
private var value: Int = 3
private var lowerLimit:Int = 0
var wrappedValue: Int {
get {
return value
}
set {
self.value = max(newValue, 0)
}
}
}
lowerLimit より小さい値をセットしようとしても、セットできないようにする property wrapper です。
変数の初期値は、3 となっていて、チェックする境界値は 0 となっています。(意味的には、負の値がセットできないようにする property wrapper となっています)
動かしてみますと、
@propertyWrapper struct WrapIntLowerLimit {
private var value: Int = 3
private var lowerLimit:Int = 0
var wrappedValue: Int {
get {
return value
}
set {
self.value = max(newValue, lowerLimit) // (7)
}
}
}
class CheckWrapInt {
@WrapIntLowerLimit var value:Int
}
var cwi = CheckWrapInt() // (1)
print(cwi.value) // (2)
cwi.value = -4 // (3)
print(cwi.value) // (4)
cwi.value = 12 // (5)
print(cwi.value) // (6)
(1) の段階で、初期値がセットされていまて、(2) で、3 と表示されることで確認できます。(表示していませんが、lowerLimit は 0 です)
(3) で -4 を設定しようとしていますが、(7) のコードにて、0 が設定されますので、(4) でも 0 と表示されます。
(5) では、12 を設定しようとしていて、(7) のコードでもそのままの 12 が設定され、(6) では、 12 と表示されます。
このようになんらかの制御を組み込もうとするケースでは、変数としての初期値の他に、制御を指定する方法(このケースでは下限値をチェックする値)に対して、初期値を設定したくなります。
複数の値を設定したいのですから、これまでのような “var value:Int = 5” のような記述方法では設定できません。
property wrapper 指定での初期値指定
propertyWrapper 修飾で property を定義するときに、propertyWrapper に対しての初期値指定を行うことができます。
class CheckWrapInt {
@WrapIntLowerLimit var value:Int = 0 // (1)
@WrapIntLowerLimit(wrappedValue: 5, lowerLimit: -5) var value2:Int // (2)
}
(2) のように propertyWrapper に対して、init のような設定を行うことができます。
少し長いですが、以下は、そのまま Plyaground で実行することができます。
@propertyWrapper struct WrapIntLowerLimit {
private var value: Int = 0
private var lowerLimit:Int = 0
init(wrappedValue:Int) {
self.value = wrappedValue
}
init(wrappedValue: Int, lowerLimit:Int) {
self.value = wrappedValue
self.lowerLimit = lowerLimit
}
var wrappedValue: Int {
get {
return value
}
set {
self.value = max(newValue, lowerLimit)
}
}
}
class CheckWrapInt {
@WrapIntLowerLimit var value:Int = 0
@WrapIntLowerLimit(wrappedValue: 5, lowerLimit: -5) var value2:Int // 変数値 5 境界値 -5 を初期値指定
}
var cwi = CheckWrapInt()
print(cwi.value)
cwi.value = -4
print(cwi.value)
cwi.value = 12
print(cwi.value)
print(cwi.value2) // 初期値である 5 が表示される
cwi.value2 = -4 // lowerLimit(-5)より大きい値をセット
print(cwi.value2) // -4 と表示される
cwi.value2 = -10 // lowerLimit(-5)より小さい値をセット
print(cwi.value2) // -5 と表示される
まとめ
- @WrapIntLowerLimit var value:Int = 0 のように変数に代入するように初期化できる
- @WrapIntLowerLimit(wrappedValue: 5, lowerLimit: -5) var value2:Int のように、property wrapper に対して直接初期化も可能
ここまでが、propertyWrapper の最小限の説明ですが、ここまでの仕組みを使って、いろいろなアクセス制御を propertyWrapper できるようになります。
ですが、ここまでの説明に、State で有名になった “$” の説明がないことに気づいたかもしれません。
$ は、projectedValue という property と関連しています。次の記事で説明予定です。
説明は以上です。
不明な点やおかしな点ありましたら、ご連絡いただけるとありがたいです。
Sponsor Link