index, AV, AppleScript, Bicycle, Cinema, DTM, Dairy, Dev, Fashion, Fitness, Game, Health, Help, Lyrics, Meal, Motor, Motorcycle, Music, Objective-C, PC, PDA, Phone, Robot, S15S, Stationary, Swift, Text, Travel, V36, Watch
MacOSX 10.3から追加されたNSUserDefaultsControllerには、setInitialValues:というメソッドが存在する。これはstandardUserDefaultsに初期設定を与えるものだろうと考え、下記のようにコーディングしてみた。
// 初期設定ウィンドウ内 // values ... 初期設定の保存されたdictionary. // valuesには'wordWrap'というキーで'YES'を表すNSNumberのインスタンスが格納されている。 id controller = [NSUserDefaultsController sharedUserDefaultsController]; [controller setInitialValues:values] ... [controller save:self];
なるほど。実際に使ってみると、設定はきちんと保存されているようだ。アプリケーションを再起動しても、問題なく設定が再現されている。
しかし、これで設定した値をアプリケーション内部から使おうとすると、なにやら妙だ。
id defaults = [NSUserDefaults standardUserDefaults]; BOOL wordWrap = [defaults boolForKey:@"wordWrap"];
wordWrapの値が、常にNOになってしまう。
アプリケーションの初期設定ファイルを観察すると、値がNOの時だけwordWrapというプロパティがNOで保存され、YESの時にはプロパティが削除され、YESの値が保存されないと分かった。
どうやら、NSUserDefaultsControllerで初期値を設定すると、初期値と異なる値が設定された時だけプロパティを保存するらしい。確かに初期設定のことだけを考えれば、これも妥当ではあるのだが… アプリケーション内部から実際の設定値を取得しようとすると、NSUserDefaultsとNSUserDefaultsControllerの両方のインスタンスに問い合わせるという無駄が生じる。できればNSUserDefaultsだけで解決できるようにしてほしいのだが…
ということで、状況を簡単にするためにNSUserDefaultsControllerの初期値は使わないことにした。その代わり、standardUserDefaultsインスタンスに初期値を設定する方法を実装する。
僕の取った方法は単純だ。取得したstandardUserDefaultsインスタンスに対して設定したいキーがあるかどうか問い合わせ、なければそのキーと初期値を追加するだけ。実装としては、設定を楽にするためにNSUserDefaultsに新しいカテゴリを設定し、専用のメソッドを追加した。
// KPrefsServer.h @interface NSUserDefaults (Preferences) - (void)setBoolIfNeeded:(BOOL)value forKey:(NSString*)key; - (void)setFloatIfNeeded:(float)value forKey:(NSString*)key; - (void)setIntegerIfNeeded:(int)value forKey:(NSString*)key; - (void)setObjectIfNeeded:(id)value forKey:(NSString*)key; @end // KPrefsServer.m @implementation NSUserDefaults (Preferences) - (void)setBoolIfNeeded:(BOOL)value forKey:(NSString*)key { if(![self objectForKey:key]){ [self setBool:value forKey:key]; } } - (void)setFloatIfNeeded:(float)value forKey:(NSString*)key { if(![self objectForKey:key]){ [self setFloat:value forKey:key]; } } - (void)setIntegerIfNeeded:(int)value forKey:(NSString*)key { if(![self objectForKey:key]){ [self setInteger:value forKey:key]; } } - (void)setObjectIfNeeded:(id)value forKey:(NSString*)key { if(![self objectForKey:key]){ [self setObject:value forKey:key]; } } @end
standardUserDefaultsへの初期値の追加は下記のようになる。
id defaults = [NSUserDefaults standardUserDefaults]; [defaults setBoolIfNeeded:YES forKey:@"wordWrap"];
これで、アプリケーション内部から問題なく初期設定にアクセスできるようになった。
NSUserDefaultsControllerは便利だが、初期設定パネルとstandardUserDefaultsとの接続のみに利用し、初期値などは指定しない方が無難だろう。