【Swift】NSUserDefaultsを便利に使う方法を幾つか

# はじめに
- `NSUserDefaults`の扱いを簡単にしたい
- `NSUserDefaults.standardDefaults()`って毎回書きたくない
- キーを文字列リテラルで指定するのが嫌だ（タイポもあるし..）

などなどの不満から、NSUserDefaultsを扱う方法についていろいろ調べてみて試行錯誤した結果を残しておきます。
タイトルに「幾つか」と書いていますが、２つだけです :sweat_smile: 

良い方法をご存知の方、ご教授ください。

# 1. `enum`でキーを定義する

[enumでNSUserDefaultsを便利に](http://qiita.com/Akkyie/items/9a5bd66951615073c080)

上記の記事を参考にさせていただき`enum`を使って`NSUserDefaults`を使う方法を考えてみました。

ほぼほぼ上記の記事通りですが、キーに対応する値の型を明確にしたかったので、型を分けるための`enum`を入れ子にして入れてみました。

```swift
enum UserDefaults {

    // Bool型の値を持つキーをcaseで定義
    enum BoolValue: String {
        case SomeFlag
        
        func set(value: Bool) {
            NSUserDefaults.standardUserDefaults().setBool(value, forKey: self.rawValue)
            NSUserDefaults.standardUserDefaults().synchronize()
        }
        
        func get() -> Bool {
            return NSUserDefaults.standardUserDefaults().boolForKey(self.rawValue)
        }
    }

    // Int型の値を持つキーをcaseで定義
    enum IntValue: String {
        case UserID
        
        func set(value: Int) {
            NSUserDefaults.standardUserDefaults().setInteger(value, forKey: self.rawValue)
            NSUserDefaults.standardUserDefaults().synchronize()
        }
        
        func get() -> Int {
            return NSUserDefaults.standardUserDefaults().integerForKey(self.rawValue)
        }
    }

    // String型の値を持つキーをcaseで定義
    enum StringValue: String {
        // ...
    }

    // 略...
    
}
```

使用時

```swift
UserDefaults.IntValue.UserID.set(1)
let userId = UserDefaults.IntValue.UserID.get() // 1
```

キーに対してどの型の値を入れるかは明確になった一方、
定義の段階においては、型ごとにgetメソッドとsetメソッドを作っているので、少々面倒ではあります。
また、使用時でも`enum`のネストが深い分、「.」つなぎが多くなってしまうという点ではちょっと使いづらくなってしまった感じがあります。


# 2. `struct`のプロパティとしてキーを定義する

２つ目ですが、こちらに関しては下記のライブラリを参考にしました。
https://github.com/radex/SwiftyUserDefaults

（そのままそのライブラリ使えよっていうのはいったん置いといて :grimacing: ）


```swift
struct UserDefaultsKeys {
    
    // ここにキーを定義していく
    static var hasLoginKey = DefaultsKey<Bool>("someFlag")
    static var userID = DefaultsKey<Int>("userID")
    
}

struct DefaultsKey<ValueType> {
    let key: String
    
    init(_ key: String) {
        self.key = key
    }
}

extension NSUserDefaults {
    
    subscript(key: DefaultsKey<Bool>) -> Bool {
        get {
            return boolForKey(key.key)
        }
        set {
            setBool(newValue, forKey: key.key)
            synchronize()
        }
    }
    
    subscript(key: DefaultsKey<Int>) -> Int {
        get {
            return integerForKey(key.key)
        }
        set {
            setInteger(newValue, forKey: key.key)
            synchronize()
        }
    }

    subscript(key: DefaultsKey<String>) -> String {
        // ...
    }
    
    // 略...
}
```

使用時

```swift
let UserDefaults = NSUserDefaults.standardUserDefaults()

UserDefaults[UserDefaultsKeys.userID] = 1
let userId = UserDefaults[UserDefaultsKeys.userID]
```

こちらも型ごとにsubscriptを書いてgetterとsetterを実装していますが、
subscriptでアクセスできる分、直感的に値のget, setを行いやすいというのはいいですね。

また、`DefaultsKey`構造体でジェネリクスを用いて様々な型を受けられるようにし、NSDefaultsの拡張でその型に対応するsubscriptを作るというのは勉強になります。


# 最後に

ほとんど自分で考えたというものではないので記事にするのもおこがましいのですが、、
`enum`や`subscript`, ジェネリクスの活用などは今回色々と考えてみて大変勉強になりました。