4
1

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

More than 3 years have passed since last update.

【Swift】UserDefaultsを扱いやすくする

Posted at

はじめに

今回はUserDefaultsをジェネリクスとプロトコルを使って少し工夫します。

やりたいこと

普通は以下のように使うと思います。

UserDefaults.standard.set("サンプル", forKey: "sampleKey") // 書き込み
let text = UserDefaults.standard.string(forKey: "sampleKey") // 読み込み

今回は以下のように、forKeyを工夫してアクセスしやすくします。

let userDefault = UserDefault<UserDefautlsKeys.Animal>()
userDefault.set(true, forKey: .dog)
let bool = userDefault.bool(forKey: .dog)

一番簡単なのは、以下のようにStringを拡張する方法です。

extension String {
    static var dog: String { return "sampleDogKey" }
    static var cat: String { return "sampleCatKey" }
}

しかし、これだとUserDefaultsのkey以外でもこの文字列を使うことができ、あまり意味がありません。
今回はUserDefaultのforKeyを設定する時のみ、このような使い方をするにはどうすればよいのかをやっていこうと思います。

実装

struct Animal {
    let dog: String
    let cat: String
}

struct Drink {
    let water: String
    let milkTea: String
    let cola: String
}

struct UserDefautlsKeys {
    enum Animal: String, UserDefautlsKeyProtocol {
        static let domain: Domain = .animal
        var id: String { self.rawValue }
        case dog
        case cat
    }
    enum Drink: String, UserDefautlsKeyProtocol {
        static let domain: Domain = .drink
        var id: String { self.rawValue }
        case water
        case milkTea
        case cola
    }
}

enum Domain: String {
    case animal
    case drink
}

protocol UserDefautlsKeyProtocol {
    static var domain: Domain { get }
    var id: String { get }
    var key: String { get }
}

extension UserDefautlsKeyProtocol {
    var key: String { Self.domain.rawValue + "." + id }
}

final class UserDefault<R: UserDefautlsKeyProtocol> {
    private let userDefaults: UserDefaults
    init(userDefaults: UserDefaults = .standard) {
        self.userDefaults = userDefaults
    }
    func set(_ value: Any?, forKey identifier: R) {
        userDefaults.set(value, forKey: identifier.key)
    }
    func bool(forKey identifier: R) -> Bool? {
        return userDefaults.bool(forKey: identifier.key)
    }
}

解説

一番のポイントはUserDefaultのジェネリクスです。これでキーの型をUserDefautlsKeyProtocolが準拠したものに限定できます。今回であれば、UserDefautlsKeysAnimalDrinkに準拠させているので、これらのkey(今回はkeyを初期設定しているので、enumの中には書かれていないが、domainとidで一意に決まる)に限定できます。
また、プロトコルを使うことでUserDefaultsKeyを抽象化し、キーを扱いやすくしています。

おわりに

おわりです。

4
1
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
4
1

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?