🌯
Swift5.1のProperty Wrappersを試す
Swift5.1(Xcode11.0)から新機能Property Wrappersが使えるようになったので試してみる。
Property Wrappersとは
- プロパティに共通機能を追加できる
- プロパティへのアクセス方法に関するAttributeをつくるためのAttribute
docs.swift.org - Property Wrappers (opens new window)
A property wrapper adds a layer of separation between code that manages how a property is stored and the code that defines a property.
Attributeとは
- @がついてるこんなやつ
- @autoclosure @escaping @convention @available @discardableResult @objc @nonobjc @objcMembers @GKInspectable @UIApplicationMain @NSApplicationMain @NSCopying @NSKeyedArchiverClassName @NSManaged @testable @IBAction @IBOutlet @IBDesignable @IBInspectable
- Swift5.1のattribute全解説|全27種 (opens new window)
Attributeをつくってみる
// 12以下を保証する
@propertyWrapper
struct TwelveOrLess {
private var number = 0
// 必須
var wrappedValue: Int {
get { return number }
set { number = min(newValue, 12) }
}
}
Attributeを使ってみる
struct SmallRectangle {
@TwelveOrLess var height: Int
@TwelveOrLess var width: Int
}
var rectangle = SmallRectangle()
print(rectangle.height) // "0"
rectangle.height = 13
print(rectangle.height) // "12"
12以外にも対応できるように拡張
Property Wrappersに初期値を与える
@propertyWrapper
struct SmallNumber {
private var maximum: Int
private var number: Int
var wrappedValue: Int {
get { return number }
set { number = min(newValue, maximum) }
}
init() {
maximum = Int.max
number = 0
}
init(wrappedValue: Int) {
maximum = Int.max
number = min(wrappedValue, maximum)
}
init(wrappedValue: Int, maximum: Int) {
self.maximum = maximum
number = min(wrappedValue, maximum)
}
}
初期値を設定する
struct Rectangle {
@SmallNumber var height: Int
@SmallNumber(wrappedValue: 0, maximum: 10) var width: Int
}
var rectangle = Rectangle()
rectangle.width = 20
print(rectangle.height, rectangle.width) // 0 10
Projected Value
Projected Valueを定義する
@propertyWrapper
struct SmallNumber {
private var number = 0
var projectedValue = false
var wrappedValue: Int {
get { return number }
set {
if newValue > 12 {
number = 12
projectedValue = true
} else {
number = newValue
projectedValue = false
}
}
}
}
Projected Valueを参照する($プロパティ名)
struct SomeStructure {
@SmallNumber var someNumber: Int
}
var someStructure = SomeStructure()
someStructure.someNumber = 4
print(someStructure.$someNumber)
// Prints "false"
someStructure.someNumber = 55
print(someStructure.$someNumber)
// Prints "true"
Property Wrappersを活用した例
marksands/BetterCodable (opens new window)
- @LossyArray: 配列の一部の要素のデコードに失敗しても成功した要素のみデコードできるようにする
- @LossyDictionary: @LossyArrayの辞書版
- @DefaultCodable: Codableに準拠した型のプロパティにデフォルト値を与える
- @DefaultFalse: DefaultCodableの簡易版、デフォルトでfalseにする
- @DefaultEmptyArray: DefaultCodableの簡易版、デフォルトで空配列にする
- @DefaultEmptyDictionary: DefaultCodableの簡易版、デフォルトで空辞書にする
- @LosslessValue: StringやInt、Boolなどプロパティの型とJSONの型が異なってもデコードできるようにする