はじめに
Swift 5.1から新しく追加されたPropertyWrapper
。
@State
や@Binding
などでお馴染みですが、カスタム属性を作成して使っているでしょうか?
今回は、WWDC2019セッションにUserDefaults
を使用したカスタム属性の内容が紹介されていたので、その例を備忘録兼ねて書こうと思います。
PropertyWrappersとは?
Swift5.1で導入されている機能で、プロパティをラップしてアクセスパターンを指定することができる機能。
すごくざっくり言うと、「プロパティにアクセスする際の面倒な処理をまとめておいて、使う時に@なんちゃら
で呼び出すことができるよ」というものです。
ちなみに@State
や@Published
などもPropertyWrappers
です。
独自に定義する場合は@propertyWrapper
を宣言して使います。
今まで
通常はこんな処理はしないと思いますが、例えばこのような処理があったとします。
struct Person {
var name: String {
get {
UserDefaults.standard.object(forKey: "person_name") as? String ?? ""
}
set {
UserDefaults.standard.set(newValue, forKey: "person_name")
}
}
}
Person
以外にも、このようなコンピューテッドプロパティを使用してUserDefaults
にアクセスするような処理が複数あったらとても冗長です。
PropertyWrappersを使う
ここでPropertyWrappers
の出番です。
PropertyWrappers
を使用してUserDefaults
のアクセスパターンを定義してみます。
(ちなみにこのUserDefaults
のアクセスパターンは冒頭で書いたように、WWDC2019セッションで紹介されている例です。)
@propertyWrapper
struct UserDefault<T> {
let key: String
let defaultValue: T
init(_ key: String, defaultValue: T) {
self.key = key
self.defaultValue = defaultValue
}
var wrappedValue: T {
get {
return UserDefaults.standard.object(forKey: key) as? T ?? defaultValue
}
set {
UserDefaults.standard.set(newValue, forKey: key)
}
}
}
こう定義することで、外部からUserDefault
でプロパティを宣言することが可能になりました。
今回の例だと、実際に@UserDefault
で定義されたプロパティにアクセスした際はこのwrappedValue
の中が呼ばれます。
@UserDefault
を使ってみる
実際に使ってみます。
先ほどPerson
クラスで定義していた処理がこんなにすっきり書くことができました。
struct Person {
@UserDefault("person_name", defaultValue: "")
var name: String
}
通常通り以下のように使用できます。
let a = Person()
a.name = "Taro"
ただ、nameプロパティも同時に初期化する場合、このままでは型がUserDefault<String>
となっているので、明示的にイニシャライザを追加してあげる必要があります。
struct Person {
@UserDefault("person_name", defaultValue: "")
var name: String
init(name: String) {
self.name = name
}
}
これで引数付きで初期化できるようになりました。
let a = Person(name: "Taro")
上の例は実用的でないので、実際に使う場合は以下のようにStaticで宣言して使う感じになるかと思います。
struct UserDefaultsConfig {
@UserDefault("isLogin", defaultValue: false)
static var isLogin: Bool
@UserDefault("username", defaultValue: "")
static var username: String
@UserDefault("age", defaultValue: 1990)
static var age: Int
}
すっきり。
UserDefaultsConfig.isLogin = true
UserDefaultsConfig.username = "Yamada Taro"
UserDefaultsConfig.age = 24
さいごに
どうでしょう。思ったより簡単でした。
PropertyWrappers
を使用することで、プロパティのアクセスパターンを繰り返し書く必要がなくなります。
そして宣言的にカスタム属性を足すだけで、その定義をプロパティに当てはめられるようになるので、よりシンプルに、完結的な記述をすることができるようになりますね。
良かったらみなさんも使ってみてください。
以上、UserDefaults
を使った例でしたが、まだまだ、理解できていないところもありますので、ご指摘やアドバイス等ありましたら、コメントしていただければと思います。
それではお読みいただきありがとうございました。