NSUserDefaultsを使うときはWrapして使うと便利

  • 95
    いいね
  • 0
    コメント
この記事は最終更新日から1年以上が経過しています。

皆さんObjective-Cを楽しんでますか?
巷ではObjective-Cの事を「変態言語」なんて呼ばれたりしているそうですが、Modern Objective-Cなんかも出てきて、すっかり「大衆的」な言語に近づいて来ました。

さてそんな訳で今回はiOS開発でよく使うNSUserDefaultsの話。
NSUserDefaultsはアプリ固有の設定情報を永続化する時などによく使われる便利なクラスです。
普通に使うとこんな感じ。

// 設定情報を保存
NSUserDefaults *userDefaults = [NSUserDefaults standardUserDefaults];
[userDefaults setObject:@"hoge" forKey:@"Name"];
[userDefaults setBool:YES forKey:@"Setting"];
[userDefaults synchronize];

// 設定情報の読み込み
NSString *name = [userDefaults objectForKey:@"Name"];
BOOL setting = [userDefaults boolForKey:@"Setting"];;

これでも問題は無いのですが、自分で使っている時に困ることがあります。

1.Keyのタイプミス
2.Key値の忘却
3.保存値の型の忘却

人は間違える生き物です。
各画面で文字列リテラルを使ってKeyを書いていればタイプミスだってあります。
ビルドの時にコンパイラが「Key値が間違ってるよ!」っと教えてはくれません。
全て開発者の責任です。

人は忘れる生き物です。
開発が進むにつれて設定情報が増えてきます。
設定情報が増えるのと比例してKeyも増え開発は混沌としてきます。

そこでNSUserDefaultsをWrapしてあげます。

Configuration.h
@interface Configuration : NSObject
+ (NSString *)name;
+ (void)setName:(NSString *)value;
+ (BOOL)setting;
+ (void)setSetting:(BOOL)value;
+ (void)synchronize;
@end
Configuration.m
@implementation Configuration
static NSString *CONFIGURATION_NAME = @"Configuration.Name";
+ (NSString *)name {
  NSUserDefaults *userDefaults = [NSUserDefaults standardUserDefaults];
  [userDefaults registerDefaults:@{CONFIGURATION_NAME : @"No Name"}];
  return [userDefaults objectForKey:CONFIGURATION_NAME];
}
+ (void)setName:(NSString *)value {
  NSUserDefaults *userDefaults = [NSUserDefaults standardUserDefaults];
  [userDefaults setObject:value forKey:CONFIGURATION_NAME];
}
static NSString *CONFIGURATION_SETTING = @"Configuration.Setting";
+ (BOOL)setting {
  NSUserDefaults *userDefaults = [NSUserDefaults standardUserDefaults];
  [userDefaults registerDefaults:@{CONFIGURATION_SETTING : @(YES)}];
  return [userDefaults boolForKey:CONFIGURATION_SETTING];
}
+ (void)setSetting:(BOOL)value {
  NSUserDefaults *userDefaults = [NSUserDefaults standardUserDefaults];
  [userDefaults setBool:value forKey:CONFIGURATION_SETTING];
}
+ (void)synchronize {
  [[NSUserDefaults standardUserDefaults] synchronize];
}
@end

こんな感じで、Wrapしてあげます。
使う側では下記の様にしてあげます。

// 設定情報を保存
[Configuration setName:@"Hoge"];
[Configuration setSetting:YES];
[Configuration synchronize];

// 設定情報の読み込み
NSString *name = [Configuration name];
BOOL setting = [Configuration setting];

呼び出し側のコード量はそれほど変わらないのですが、

1.Xcodeのインテリセンスが効くのでタイプミスを防げる。
2.Xcodeのインテリセンスが効くのでKey値を覚えていなくても選ぶだけ。
3.型は戻り値や引数で決まっているので間違った型を渡す心配はなし。

また設定情報の呼び出しで[userDefaults registerDefaults:@{CONFIGURATION_NAME : @"No Name"}];と書いておくことで設定情報の初期値を設定できるので呼び出し側で初期値を意識する必要がありません。

今回の記事を書くにあたって作ったサンプルソースをgithubにあげておきます。
ConfigurationSample

Pl*ease enjoy the **d*evelopment.

この投稿は iOS Advent Calendar 2012 / Aug9日目の記事です。