woshidan's blog

あいとゆうきとITと、とっておきの話。

iOSでファイルにオブジェクトの状態を保存する/.plistとは

ObjCのコードを読んでいた時に書いたメモを放流。

アーカイブとは

プログラムで使われている複数のオブジェクトを、その属性値や相互の関係も含めてファイルに保存したり、他のプロセスに渡したりしたい場合があります。 そのために、互いに関連するオブジェクトをバイト列に変換する機能をアーカイブといい、さらにバイト列から元のオブジェクトを復元する機能をアンアーカイブといいます。 また、オブジェクトを変換して得られたバイト列をアーカイブと呼ぶことも。

一方、シリアライゼーションはプロパティーリスト程度の単純な階層構造しか表現できません。

アーカイブができるオブジェクトは、NSCodingプロトコルに適合するように実装する必要があります。

// アーカイブ用
- (void)encodeWithCoder:(NSCoder *)coder
{
  [super encodeWithCoder:coder];
  // スーパークラスがNSCodingプロトコルに適合していない場合は不要

  [coder encodeObject:オブジェクト forKey:キー文字列];
  // またはencodedConditionalObject:forKey:を使う

  ...
  [coder encodeDouble:実数の変数 forKey:キー文字列];
  // いくつかの方に合わせたメソッドが用意されている
}
// オブジェクトがまた依存しているオブジェクト...とたどっていくと元のオブジェクトのencode...が
// 呼ばれそうだが、すでにアーカイブされていたら二度目はされないらしい
// アンアーカイブ用
- (id)initWithCoder:(NSCoder *)coder
{
  self = [super initWithCoder:coder];
  // スーパークラスがNSCodingプロトコルに適合していない場合は[super init]でよい

  変数 = [[coder decodeObjectForKey:キー文字列] retain];

  ...
  変数 = [coder decodeDouble:キー文字列];
}

NSKeyedArchiver

上記のencodeWithCoderを使って、対象となるオブジェクトをエンコードした結果をデータオブジェクトに書き込み。 初期化の際は、書き込み先のNSMutableDataのオブジェクトが必要となります。

一つずつアーカイブしていっても良いが、ルートオブジェクトをエンコードすると再起的にオブジェクトグラフがアーカイブ化される。全部完了したらfinishEncodingを読んで後処理をします。

書き込み先はデータオブジェクトなのでデータオブジェクトからファイルへ書き込んだり、他プロセスへ送信したりができるし、ファイルに書き込むまで一括で出来るメソッドもあります。

NSKeyedUnarchiver

上記のinitWithCoderを使って、アーカイブされたオブジェクトが書き込まれたデータオブジェクトからオブジェクトを復元します。 ファイルからデータオブジェクトを作って読み込んだりもできます。

.plist

https://developer.apple.com/library/content/documentation/General/Reference/InfoPlistKeyReference/Articles/AboutInformationPropertyListFiles.html http://glassonion.hatenablog.com/entry/20110910/1315609950 http://qiita.com/hp0me/items/b619680611fd6667273f

Apple系が発祥のNSPropertyListSerializationクラスでパースできる*1、データ永続化などのために使われるファイル形式。 プロパティリストと呼ぶみたいです。

代表的なものはアプリの設定を保存している Info.plist だが、それ以外にも利用可能なようです。 ファイル形式としてはXMLの一種だと思います。*2

*1:NSArray や NSDictionary クラスでもまぁできる

*2:そういえば、AndoridのSharedPreferencesの実装もXMLだったはず http://qiita.com/ochim/items/dc4d77d478e87c1449ad