NSDictionaryをNSMutableDictionaryに変換する しかも再帰的に


NSUserDefaultでアプリケーションの状態を保存するときにNSDictionaryを使う。
このときNSDictionaryを階層構造にしたいということがよくあるのではなかろうか。僕の場合、UIFontのkeyを1つ作ってその下にfontNameとpointSizeを置くような構造にしたかった。つまり、例えば、

NSMutableDictionary* font = [NSMutableDictionary dictionaryWithObjectsAndKeys: @”Helvetica”, @”name”, @”15″, @”size”, nil];

というのをまず作っておく。ブログ entry に、titleとcommentがあって、それぞれのフォント情報を記録するために、このfont を使う。つまり、

NSMutableDictionary* entrySet = [NSMutableDictionary dictionaryWithObjectsAndKeys:font,@”titleFont”,font,@”commentFont”, nil];

のように階層構造にするわけだ。
そして、これをNSUserDefault に保存する。

NSUserDefaults* userDefaults = [NSUserDefaults standardUserDefaults];
[userDefaults setObject:entrySet forKey:@”entrySet”];

以上は、初期化時の処理で、運用上は、userDefaultsからentrySetを読み出し参照する。
問題は、これを変更する手順だ。

読み出すときは NSDictionary で読み出すことになる。
NSDictionary* entrySet = [userDefaults dictionaryForKey:@”entrySet”];

でも、NSMutableDictionaryでないと中身の変更はできないから、NSDictionaryをNSMutableDictionaryに変更しなければならない。やっぱり、copyを作るしかないだろうか。だから例えば、

NSMutableDictionary* entrySet = [[[userDefaults dictionaryForKey:@”entrySet”] mutableCopy] autorelease];

ということ?いや階層化してしまっているので、そんな簡単じゃない。これでは中の font が mutable になっていないのである。
自分で階層をトレースして変換していく再帰処理関数を作ろうか?いやいやきっとだれかがやっているはずと思って検索したらあった。

deep mutable copy of a NSMutableDictionary

このページを最後まで読むと、なんと、自分で再帰処理を書く必要さえないのだとわかる。上の例の場合、

NSMutableDictionary *entrySet = (NSMutableDictionary *)CFPropertyListCreateDeepCopy(kCFAllocatorDefault, (CFDictionaryRef)[userDefaults dictionaryForKey:@”entrySet”], kCFPropertyListMutableContainers);

となる。まったくすばらしい!

広告