読者です 読者をやめる 読者になる 読者になる

A Day In The Life

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

NSUserDefaults を使ったデータの保存方法

objective-c/objc ios

iOS でデータを永続化する方法の続きです。今回は NSUserDefaults クラスを使ったデータの永続化方法について説明します。このクラスを使うと簡単にデータの保存と読み込みが出来るのでアプリ開発で頻繁に使用されています。

NSUserDefaults って何?

アプリ固有の設定値を保存することに特化したクラスです。アプリ開発者は NSUserDefaults オブジェクトを通して Key-Value 形式でデータにアクセスします。データの保存場所の管理は NSUserDefaults オブジェクトがすべて行ってくれます。
実際のデータは ホーム/Library/Preferences 以下にプロパティリスト形式で保存されます。

データの保存と取得で使用するメソッド

NSUserDefaults クラスにはデータ型に応じて以下の保存と取得メソッドが定義されています。

オブジェクトの型 保存メソッド 取得メソッド
オブジェクト全般(id型) setObject: forKey: objectForKey:
NSString setObject: forKey: stringForKey:
NSArray setObject: forKey: arrayForKey:
NSArray(文字列) setObject: forKey: stringArrayForKey:
NSDictionary setObject: forKey: dictionaryForKey:
NSData setObject: forKey: dataForKey:
NSInteger setInteger: forKey: integerForKey:
float setFloat: forKey: floatForKey:
double setDouble: forKey: doubleForKey:
BOOL setBool: forKey: boolForKey:
NSURL(iOS4 から追加) setURL: forKey: URLForKey:

NSUserDefaults を使ってデータを保存する

それでは具体的に NSUserDefaults オブジェクトを使ってデータを保存する方法を見ていきましょう。standardUserDefaults メソッドを使って NSUserDefaults オブジェクトを取得してからデータを保存します。synchronize メソッドを呼んでデータをプロパティリスト書き出します。
以下は setObject: forKey: メソッドを使った保存の例です。

NSArray *array = @[@"http://www.apple.com", @"http://www.9revolution9.com", @"https://twitter.com/"];
NSUserDefaults *defaults = [NSUserDefaults standardUserDefaults];
[defaults setObject:array forKey:@"bookmarks"];
BOOL successful = [defaults synchronize];
if (successful) {
  NSLog(@"%@", @"データの保存に成功しました。");
}

synchronize メソッドを呼びださなくてもプロパティリストへの書き出しは OS 側のタイミングで自動的に行われます。すぐにプロパティリストに書き出したい場合のみ呼ぶようにしましょう。

NSUserDefaults に保存されたデータを取得する

NSUserDefaults に保存されているデータを取得する方法を見てみましょう。
以下は NSArray オブジェクトのデータを取得する例です。

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

初期値を設定する

NSUserDefaults オブジェクトの registerDefaults: メソッドを使うと NSDictionary 形式で初期値を設定することが出来ます。
このメソッドはあくまで初期値の設定に使うためのメソッドで、このメソッドを使って保存したデータはメモリ上にしか保存されず synchronize メソッドを呼び出してもプロパティリストに書き込まれることはありません。registerDefaults: メソッドを使って設定した初期値はアプリを終了すると消えてしまいますので使う時は注意してください。
以下その例です。

NSUserDefaults *defaults = [NSUserDefaults standardUserDefaults];
NSDictionary *dict = @{
  @"home" : @"http://www.google.co.jp",
  @"bookmarks": @[@"http://www.apple.com", @"http://www.9revolution9.com", @"https://twitter.com/"],
  @"font-size" : @14,
  @"javascript-enabled" : @(YES)
};
[defaults registerDefaults:dict];
// synchronize メソッドは失敗する
NSLog(@"synchronize:%d", [defaults synchronize]);
NSLog(@"%@", [defaults objectForKey:@"home"]);
NSLog(@"%@", [defaults objectForKey:@"bookmark"]);
NSLog(@"%d", [defaults integerForKey:@"font-size"]);
NSLog(@"%d", [defaults boolForKey:@"javascript-enabled"]);

出力結果は以下のようになります。

SampleProject[7337:707] synchronize:0
SampleProject[7337:707] http://www.google.co.jp
SampleProject[7337:707] (
    "http://www.apple.com",
    "http://www.9revolution9.com",
    "https://twitter.com/"
)
SampleProject[7337:707] 14
SampleProject[7337:707] 1

保存できるデータの種類

NSUserDefaults で保存できるデータの種類は以下の通りです。
プロパティリスト形式なので保存できるデータの種類も NSURL を除いてプロパティリストと同じです。

  • NSString
  • NSNumber
    実数型、数値型、ブール型に対応
  • NSData
  • NSDate
  • NSArray
  • NSDictionary
  • NSURL(iOS4 から対応)
    ただしNSArray や NSDictionary オブジェクトにネストして保存することは出来ない。

保存したデータの削除

保存したデータは NSUserDefaults クラスの removeObjectForKey: メソッドで削除できます。データを削除する時は synchronize メソッドを使って削除結果をすぐにプロパティリストに反映させるのがよいでしょう。
以下その例です。

NSUserDefaults *defaults = [NSUserDefaults standardUserDefaults];
[defaults removeObjectForKey:@"bookmarks"];
BOOL successful = [defaults synchronize];
if (successful) {
  NSLog(@"%@", @"データの削除に成功しました。");
} else {
  NSLog(@"%@", @"削除するデータがありません。");
  return;
}
// データが削除されていることを確認する
NSArray *array = [defaults arrayForKey:@"bookmarks"];
NSLog(@"%d:%@", successful, array);
if (!array) {
  NSLog(@"%@", @"データは削除されました。");
}

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

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

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

Person *tYamada = [[[Person alloc] init] autorelease];
tYamada.name = @"山田太郎";
Address *yAddress = [[[Address alloc] init] autorelease];
yAddress.zipCode = @"104-0061";
yAddress.state = @"東京都";
yAddress.city = @"中央区";
yAddress.other = @"銀座1丁目";
tYamada.address = yAddress;
// tYamadaオブジェクトをアーカイブする
NSData *data = [NSKeyedArchiver archivedDataWithRootObject:tYamada];

NSUserDefaults *defaults = [NSUserDefaults standardUserDefaults];
[defaults setObject:data forKey:@"address"];
BOOL successful = [defaults synchronize];
if (successful) {
  NSLog(@"%@", @"データの保存に成功しました。");
}

NSUserDefaults はどんなデータを保存するのに向いているのか

NSUserDefaults はプロパティリストを直接扱うのに比べてプログラムからデータの編集がしやすくなるのが特徴です。
個人的には自作プロパティリストには読み取り専用のデータを保存、NSUserDefaults にはユーザがアプリ上で設定可能なデータを保存するという使い分けをしています。
NSUserDefaults を使えば簡単にデータを保存できますが、ファイルにデータを保存しているのでメモリに比べてデータの保存や読み込みは遅くなります。簡単なのでつい何でも保存したくなりますが実行速度が気になる場合やアプリ終了時に消えても良いデータはメモリに保存するようにしましょう。

改訂履歴

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

サンプルプログラム

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