A Day In The Life

とあるプログラマの備忘録

iOS でプロパティリストを使ったデータの保存方法

iOS でオブジェクトをシリアライズする方法に続き今回もデータ永続化方法の紹介です。
iOS にはプロパティリストと呼ばれるファイル形式があります。プロパティリストは NSArray や NSDictionary クラスを使って簡単にデータの読み書きができます。
ここではプロパティリストを使った基本的なデータの保存方法から自作クラスのオブジェクトを保存する方法まで説明します。

プロパティリストって何?

プロパティリストは Mac OS XiOS で利用することができるデータ永続化のためのファイル形式です。Mac OS X ではもっぱらユーザの情報を設定するのに使われる事が多く Windowsレジストリのような使われ方をしています。iOS では Info.plist のようにアプリの情報を設定するのに使われることが多いです。
またプロパティリストはファイルの拡張子が .plist になってるため plist ファイルと呼ばれることもあります。
プロパティリストは汎用性が高くデータの読み書きもプログラムから簡単にできるので、アプリの設定以外にもプログラム上でデータを保存するのに使用されます。
プロパティリスト形式のデータは Property List Editor という専用のエディタで手軽にデータの編集ができるのも特徴です。人間の目で見てわかるデータの管理に向いています。
Property List Editor
プロパティリスト全体は NSArray または NSDictionary 型で保存する必要があります(おおもとのデータの型が NSArray か NSDictionary でなければならないという意味です)。NSArray や NSDictionary のデータにさらに NSArray または NSDictionary のデータをネストすることもできます。

プロパティリスト形式でデータを保存する

それではプロパティリストを使ったデータの保存方法を見ていきましょう。
プロパティリストにデータを保存するには NSArray と NSDictionary クラスの writeToFile: メソッドを使います。
以下は NSArray クラスの writeToFile: メソッドを使ったデータ保存の例です。

NSArray *paths = NSSearchPathForDirectoriesInDomains(NSDocumentDirectory, NSUserDomainMask, YES);
NSString *directory = [paths objectAtIndex:0];
NSString *filePath = [directory stringByAppendingPathComponent:@"data.plist"];
    
NSArray *array = @[@"北海道", @"青森県", @"岩手県", @"秋田県"];
BOOL successful = [array writeToFile:filePath atomically:NO];
if (successful) {
  NSLog(@"%@", @"データの保存に成功しました。");
}

保存されたデータは XML 形式で保存されています。実際のデータを見ると以下のようになっています。

<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
<plist version="1.0">
<array>
  <string>北海道</string>
  <string>青森県</string>
  <string>岩手県</string>
  <string>秋田県</string>
</array>
</plist>

プロパティリスト形式のファイルを読み込む

プロパティリストファイルからデータを読み込むには initWithContentsOfFile: メソッドを使います。
以下がその例です。

NSArray *array = [[NSArray alloc] initWithContentsOfFile:filePath];
if (array) {
  for (NSString *data in array) {
    NSLog(@"%@", data);
  }
} else {
  NSLog(@"%@", @"データが存在しません。");
}

保存できるデータの種類

さきほども説明した通りおおもとのデータは NSArray か NSDictionary 型でないといけませんがその下の階層に保存できるデータの種類は複数あります。
プロパティリストで保存できるデータの種類は以下の通りです。

  • NSString
  • NSNumber
    実数型、数値型、ブール型に対応
  • NSData
  • NSDate
  • NSArray
  • NSDictionary

自作クラスのオブジェクトを保存する

プロパティリストは通常自作クラスのオブジェクトを保存することは出来ませんが、オブジェクトをアーカイブして NSData オブジェクトに変換することで保存できるようになります。
オブジェクトのアーカイブ方法の詳細は以下の記事を参照してください。

下記プログラムは「iOS でオブジェクトをシリアライズする方法」で作成した Person と Address クラスのオブジェクトをプロパティリストに保存する例です。

Person *tYamada = [[Person alloc] init];
tYamada.name = @"山田太郎";
Address *yAddress = [[Address alloc] init];
yAddress.zipCode = @"104-0061";
yAddress.state = @"東京都";
yAddress.city = @"中央区";
yAddress.other = @"銀座1丁目";
tYamada.address = yAddress;

// 注意!tYamada オブジェクトをそのまま保存することはできない
// NSArray *array = @[tYamada];
NSData *data = [NSKeyedArchiver archivedDataWithRootObject:tYamada];
NSArray *array = @[data];
BOOL successful = [array writeToFile:filePath atomically:YES];
if (successful) {
  NSLog(@"%@", @"データの保存に成功しました。");
}

プロパティリストに保存された自作クラスのオブジェクトを読み込む

プロパティリストからデータを読み込む時は NSArray クラスの initWithContentsOfFile: メソッドで NSArray オブジェクトを生成した後、NSKeyedUnarchiver クラスの unarchiveObjectWithData メソッドを使って復元します。
以下はその例です。

NSArray *array = [[NSArray alloc] initWithContentsOfFile:filePath];
if (array) {
  for (NSData *data in array) {
    Person *person = [NSKeyedUnarchiver unarchiveObjectWithData:data];
    NSLog(@"%@", person);
  }
} else {
  NSLog(@"%@", @"データが存在しません。");
}

プロパティリストはどんなデータを保存するのに向いているのか

プロパティリストの特徴はなんと言っても Property List Editor で手軽にデータの編集ができることです。
プロパティリストはプログラムで定数定義するには少し多いデータ(都道府県名リスト的なものなど)やプログラム上から変更することのないアプリ固有の設定情報などを保存するのに向いています。
NSKeyedArchiver を使ってバイナリを保存することもできますが Property List Editor で編集できないのであまり向いていません。

改訂履歴

2012年7月29日 記事内容を見直し修正。Modan Objective-C Syntax に対応

サンプルプログラム

記事で使用したサンプルプログラムを以下に置いておきます。