Posted at
RealmDay 16

NSUserDefaultsの代わりにRealmを使ってみると良いかもしれない

More than 3 years have passed since last update.


NSUserDefaultsの代わりにRealmを使ってみると良いかもしれない

iOSアプリ内に何らかの設定値を保存する場合、基本的にNSUserDefaultsに保存しているかと思います。

ただしNSUserDefaultsは、[String:AnyObject]でアクセスしなければならず、Swiftでは結構扱いにくいです(ラッパークラスをうまく設計できていれば問題は起きないのかもしれませんが)。

それから色々な場所から色々なkeyで値が保存されるため、気がついたらどこに何が入っているか分からないということにも起きがちちゃないのではないでしょうか。

いろいろ考えてみたのですが、Realmを使うと"アプリの構造"を扱いやすくなるのではないのか、と思いました。こちらの記事でも同様のことが述べられています。

ということでRealmSwift簡単なサンプルを書いてみました。


サンプルコード解説

シンプルにユーザーの状態(ゲスト状態かログイン状態か)と、起動した日時を記録しようと思います。

サンプルではユーザーの状態をenumで定義しています。


AppPreferences.swift

enum UserState: String {

case Guest, Login
}

Realmではenumはプロパティとして扱えないので、enumrawValueStringにしてプロパティに代入します。

そしてObjectを継承してAppStateを定義します。


AppPreferences.swift

class AppState: Object {

dynamic var state: String = UserState.Guest.rawValue
dynamic var launchDateTime: NSDate = NSDate()
}

以下のようなSingletonのRealmのラッパークラスを作成します。


AppPreferences.swift

final class AppStateManager {

static let sharedInstance = AppStateManager()
private init() {}

private var realm: Realm {
guard let realm = try? Realm() else {
fatalError()
}
return realm
}

func update(userState: UserState ,launchDateTime: NSDate) {

let state = AppState()
state.state = userState.rawValue
state.launchDateTime = launchDateTime

do {
try self.realm.write({ [weak self] () -> Void in

guard let stateManager = self else {
return
}

stateManager.realm.add(state)
})
} catch {
print("could not write")
}
}
}


こんな感じでアプリ起動時にRealmへ保存を行います。


AppDelegate.swift

    func application(application: UIApplication, didFinishLaunchingWithOptions launchOptions: [NSObject: AnyObject]?) -> Bool {

AppStateManager.sharedInstance.update(UserState.Guest, launchDateTime: NSDate())
return true
}

AppDelegateoptional func application(_ application: UIApplication,

didFinishLaunchingWithOptions launchOptions: [NSObject : AnyObject]?) -> Bool
で呼び出すことを想定しています。


まとめ

UserDefaultsにRealmを使ってみることについて考えてみましたが、実際に使う際には結構リスクが高位のだろうなとも感じました。リスクを考慮した上で、許容できるのであれば、個人的には良い解決方法になるのではないかなと思います。

以下に個人的に感じたメリット、デメリットについてまとめてみました。


メリット



  • AppStateなどの状態をモデルとして定義することで、どんな情報が保存されているのかが構造化されて分かりやすい


  • NSUserDefaultsから取り出す際のキャストが不要


  • 条件を指定して保存したデータの絞り込みがしやすい


デメリット


  • Realmが1.0を迎えていない現段階ではリスクになりそう

  • 既存のアプリに途中から入れることは難しそう

  • マイグレーション怖い


補足

僕はあまりDB周りは得意ではないので、もっと色々なことがメリット、デメリット考えられるかと思うので、ご指摘いただけると嬉しいです。