KVC, Key-Value Coding

PantherあたりからCocoaフレームワークに用意されている機構にKey-Value Codingというものがある。
ある方向からの理解は、オブジェクトMyObjectに

  • (void)setHoge:(id)object ;
  • (id)hoge ;

というメソッドの組があったときに、これをプロパティhogeとし、

  • [MyObject setValue:object forKey:@"hoge"];
  • [MyObject valueForKey:@"hoge"];

でアクセスできるというものである。


もちろん実際はこれに限らなくて、NSMutableDictionaryの場合は上の二つはsetObject:ForKey:とobjectForKey:に等しいし、あるいはプロパティが要求されたけれどもメソッドが無い場合に呼ばれるsetValue:ForUndefinedKey:とvalueForUndefinedKey:というものもある。


ではこれの何が便利なのか?というと、あんまり単体では使いどころがない。
強いて言えばインターフェースや実装に非依存で動けるというところだろうか。


Thousandを作るにあたって、これをちょっと利用してみることにした。
オブジェクトの永続化に使えないかと思ったのだ。
NSArrayやNSDictionaryは、中身がNSString、NSNumber、NSDate、NSDataなんかであればプロパティリストファイル(.plist)に書き出し、また読み込むことが出来る。
都合のいいことにKey-Value codingでは、intやfloatを扱うメソッドでも、valueForKey:によってNSNumberに自動変換されたりする。
これを組み合わせれば、オブジェクトをNSDictionaryの形に変換した後にplistに書き出すことが出来る。
クラス名も併せて保存すれば、完全に復活が可能だ。


どう実装するか?であるが、

  • オブジェクト自身の使用可能なプロパティのキーを返すメソッドをプロトコルで定義
  • NSObjectに、NSDictionaryとの変換を行うメソッドをカテゴリで追加

することにした。
最初のプロトコルに適合してさえいれば、入れ子になっていたとしても全てNSDictionaryの形に変換したり、復活したり、あるいは既存のオブジェクトにプロパティを反映させることが出来る。
もちろん既存のシリアライズの仕組みもあるのだけれど、格段にコードを書く手間が減る。


で、これをオブジェクトの保存に関するほとんど全てのところで使っている。

  • ブックマーク、スレッドリストをplistに保存
  • アプリケーションの環境設定を保存(NSDictionaryにした後NSDefaultsに入れる)
  • プラグインの環境設定を保存

自分にとっては超絶便利なのだが、車輪の再発明をしている気もなくはない。