何をしたいか
こういうenumの配列junctionsをuserDefaultsに保存/読取したい場合、どう書くとシンプルか。ちょっとメモを書いてみました。
let junctions:[Light] = [.red, .green, .yellow, green]
enum Light {
case green, yellow, red
}
(例なので、どうでよいですが、、、junctionsは交差点の信号機の色を持つ配列で、三色を定義しているenumが入っている程度に思ってください。)
enumを文字列に変換する
userDefaultsはenumをそのまま扱えませんが、文字列は扱えます。
enumを文字列に変換してから、userDefaultsで扱います。
値型にStringを指定すれば、Light.green.rawValue→"green"を取得できますね。
enum Light: String {
case green, yellow, red
}
Light.green.rawValue // "green"
以前見たコードで
enum Light: String {
case green = "green",
case yellow = "yellow",
case red = "red"
}
というのがありましたが、同じ働きです。最初のコードのほうがシンプル。
保存する
let kJunctionsKey: String = "JUNCTIONS"
func save(_ junctions: [Light]) {
let userDefaults = UserDefaults.standard
let stringJunctions: [String] = junctions.map({ $0.rawValue })
userDefaults.set(stringJunctions, forKey: kJunctionsKey)
userDefaults.synchronize()
}
save(junctions: [.red, .green, .yellow, green])
//あるいは 配列junctionsについて
save(junctions)
forでループを回すよりも、map()を使うほうが読みやすいです。
使う箇所で、save(junctions: junctions)
になりがちな場合は、func save(_ junctions: [Light])
として、第一引数ラベルを省略するほうが良いと思います。save(junctions)
で済みます。
読み取る
func junctions() -> [Light]? {
let userDefaults = UserDefaults.standard
guard let stringJunctions = userDefaults.array(forKey: kJunctionsKey) as? [String] else {
return nil
}
return stringJunctions.flatMap({ Light(rawValue: $0) })
}
junctions() // [.red, .green, .yellow, green]
戻り値をNon-Optionalな[Light]型にして、nilではなく、[]を戻すようなコードも考えられます。ですが、エラーなのか空文字列なのか混乱する元なので、変換できなかった場合はnilを戻すようにしています。
配列名をそのまま関数名にしています。getJunctions()
という命名もありえますが、冗長かもしれません。
お気づきの点があれば
コメント/修正プルリクエストいただけると嬉しいです。