Persistence(15)~Core Dataでの保存(2)

2011. 07. 23
続いてソースファイルCore_Data_PersistenceAppDelegate.mに追加される内容を見てみます。
(太字が追加された部分)

#import "Core_Data_PersistenceAppDelegate.h"

@implementation Core_Data_PersistenceAppDelegate

@synthesize window;

#pragma mark -
#pragma mark Application lifecycle

- (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions {

    [self.window makeKeyAndVisible];

    return YES;
}

- (void)applicationWillResignActive:(UIApplication *)application {
}

- (void)applicationDidEnterBackground:(UIApplication *)application {
    [self saveContext];
}

- (void)applicationWillEnterForeground:(UIApplication *)application {
}

- (void)applicationDidBecomeActive:(UIApplication *)application {
}

- (void)applicationWillTerminate:(UIApplication *)application {
    [self saveContext];
}

- (void)saveContext {

    NSError *error = nil;
    NSManagedObjectContext *managedObjectContext = self.managedObjectContext;
    if (managedObjectContext != nil) {
        if ([managedObjectContext hasChanges] && ![managedObjectContext save:&error]) {

            NSLog(@"Unresolved error %@, %@", error, [error userInfo]);
            abort();
        }
    }
}

#pragma mark -
#pragma mark Core Data stack

- (NSManagedObjectContext *)managedObjectContext {

    if (managedObjectContext_ != nil) {
        return managedObjectContext_;
    }

    NSPersistentStoreCoordinator *coordinator = [self persistentStoreCoordinator];
    if (coordinator != nil) {
        managedObjectContext_ = [[NSManagedObjectContext alloc] init];
        [managedObjectContext_ setPersistentStoreCoordinator:coordinator];
    }
    return managedObjectContext_;
}

- (NSManagedObjectModel *)managedObjectModel {

    if (managedObjectModel_ != nil) {
        return managedObjectModel_;
    }
    NSURL *modelURL = [[NSBundle mainBundle] URLForResource:@"Core_Data_Persistence" withExtension:@"momd"];
    managedObjectModel_ = [[NSManagedObjectModel alloc] initWithContentsOfURL:modelURL];
    return managedObjectModel_;
}

- (NSPersistentStoreCoordinator *)persistentStoreCoordinator {

    if (persistentStoreCoordinator_ != nil) {
        return persistentStoreCoordinator_;
    }

    NSURL *storeURL = [[self applicationDocumentsDirectory] URLByAppendingPathComponent:@"Core_Data_Persistence.sqlite"];

    NSError *error = nil;
    persistentStoreCoordinator_ = [[NSPersistentStoreCoordinator alloc] initWithManagedObjectModel:[self managedObjectModel]];
    if (![persistentStoreCoordinator_ addPersistentStoreWithType:NSSQLiteStoreType configuration:nil URL:storeURL options:nil error:&error]) {
        NSLog(@"Unresolved error %@, %@", error, [error userInfo]);
        abort();
    }

    return persistentStoreCoordinator_;
}

#pragma mark -
#pragma mark Application's Documents directory

- (NSURL *)applicationDocumentsDirectory {
    return [[[NSFileManager defaultManager] URLsForDirectory:NSDocumentDirectory inDomains:NSUserDomainMask] lastObject];
}


#pragma mark -
#pragma mark Memory management

- (void)applicationDidReceiveMemoryWarning:(UIApplication *)application {
}

- (void)dealloc {

    [managedObjectContext_ release];
    [managedObjectModel_ release];
    [persistentStoreCoordinator_ release];


    [window release];
    [super dealloc];
}

@end

7425

1)saveContextメソッドの呼び出し

アプリケーションがバックグラウンドになった際に呼び出されるapplicationDidEnterBackground:と、アプリケーションが終了する直前に呼び出されるapplicationWillTerminate:で、管理オブジェクトコンテキストを永続ストアに保存するsaveContextメソッドが呼び出されています。

2)saveContextメソッドの追加

saveContextは、管理オブジェクトコンテキストを取得して保存するメソッドです。

コンテキストが存在しない場合は何もしません。

まず、後述する(ヘッダファイルで宣言したプロパティのゲッタである)managedObjectContextメソッドで管理オブジェクトコンテキストを取得します。

コンテキストが存在する場合は、hasChangeメソッドでコンテキストの変更の有無と、save:メソッドで未保存の変更の保存を試みた成否を判定します。

コンテキストが存在し、コンテキストに変更が加えられていて且つ保存ができなかった場合は、NSLogでエラーを出力し、abort()で異常終了します。
(abort()については『Programming Place Plus/C言語編 第65章 終了関数』を参照してください)

hasChanges

- (BOOL)hasChanges

レシーバの変更がコミットされていないかを示すブール値を返します。

戻り値は、レシーバの変更がコミットされていない場合はYES、そうでない場合はNOを返します。

Mac OS X v10.6以降では、このプロパティはキー値監視に準拠しています。
(『Key-Value Observing Programming Guide』参照)

Mac OS X v10.6より前では、このプロパティはキー値監視に準拠しておらず、例えばCocoaバインディングを使用している場合、管理オブジェクトコンテキストのhasChangeプロパティへバインドすることはできません。

キー値監視(KVO)を使用してこのプロパティを監視する場合、コンテキストに触れないようにするか、または通知のためにobserveValueForKeyPath:ofObject:change:context:の実装でそのオブジェクトを含める必要があります。

(これはKVO通知のロケーションが複雑なためで、例えばコンテキストはアンドゥの操作やマージの競合を修復している途中の可能性があるからです)

hasChangesの値が変化した結果として、その変更された管理オブジェクトのコンテキストへメッセージを送信する場合は、その後でコールスタックをアンワインドする必要があります。
(通常、performSelector:withObject:afterDelay:または類似したメソッドを使用します)

save:

- (BOOL)save:(NSError **)error

永続ストアへ登録されたオブジェクトへの未保存の変更をコミットしようと試みます。

戻り値は、保存が成功した場合はYES、それ以外はNOを返します。

(例えば、いくつかの編集されたオブジェクトが検証に失敗した場合など)複数のエラーが発生した場合、複数のエラーが示されたNSErrorの記述が返され、userInfo辞書にキーNSDetailedErrorsが含まれます。

NSDetailedErrorsキーに関連付けられた値は、個々のNSErrorオブジェクトを含む配列です。

error:NSErrorオブジェクトへのポインタです。
NSErrorオブジェクトを生成する必要はありません。
NULLを渡した場合、最初の失敗の後に保存処理が中断します。

3)managedObjectContextメソッドの追加

managedObjectContextはアプリケーション用の管理オブジェクトコンテキストを返すメソッドで、コンテキストが存在していない場合は生成し、アプリケーションの永続ストアコーディネータに関連付けします。

最初にコンテキストのインスタンス変数managedObjectContext_の存在の有無を判別し、あればそのままコンテキストを返します。

コンテキストが無い場合は、後述する(ヘッダファイルで宣言したプロパティのゲッタである)persistentStoreCoordinatorメソッドで永続ストアコーディネータを取得します。

コーディネータが存在する場合は、managedObjectContext_を生成・初期化してsetPersistentStoreCoordinator:メソッドでコーディネータを設定し、無い場合はそのままmanagedObjectContext_を返します。

setPersistentStoreCoordinator:

- (void)setPersistentStoreCoordinator:(NSPersistentStoreCoordinator *)coordinator

レシーバの永続ストアコーディネータを設定します。

コーディネータは管理オブジェクトモデルの提供し、永続性を処理します。

複数のコンテキストがコーディネータを共有できることに注意してください。

coordinatorがnilの場合、このメソッドは例外を発生させます。

永続ストアコーディネータからコンテキストを『切断』する場合、単純にコンテキストへの全ての参照を解放するだけでなく、正常に割り当てを解除する必要があります。

coordinator:レシーバの永続ストアコーディネータ

4)managedObjectModelメソッドの追加

managedObjectModelはアプリケーション用の管理オブジェクトモデルを返すメソッドで、モデルが存在しない場合はアプリケーションのモデルから生成します。

最初にモデルのインスタンス変数managedObjectModel_の存在の有無を判別し、あればそのままモデルを返します。

モデルが無い場合は、mainBundleメソッドでアプリケーションバンドルの位置を取得し、URLForResource:withExtension:メソッドでモデルファイルの場所を特定します。

URLForResource:withExtension:メソッドの第一引数のnameはプロジェクト名が流用され、第二引数のextensionはモデルファイルが入っているディレクトリを表す『momd』が指定されています。

Core Dataのファイル『Core_Data_Persistence.xcdatamodel』は、Xcodeの『グループとファイル』ではResourceグループの直下ではなく、『Core_Data_Persistence.xcdatamodeld』の下に置かれています。

これは、アプリケーションバンドル内では『Core_Data_Persistence.momd』フォルダ内にモデルファイル『Core_Data_Persistence.mom』があるという形になります。

iPhone OS 3.x用のサンプルコードのように、Resourceグループ直下にモデルファイル『Core_Data_Persistence.xcdatamodel』を置いた場合、アプリケーションバンドル内にディレクトリ『Core_Data_Persistence.momd』は生成されず、モデルファイル『Core_Data_Persistence.mom』がそのまま置かれる形になります。

『~.xcdatamodeld』はモデルファイルのバージョン管理を行うためのもので、モデルをバージョンアップすると『~.xcdatamodeld』グループ下に新たなモデルファイル『~.xcdatamodel』が作成されることになります。

つまりiPhone OS 3.x用のサンプルコードでは、モデルファイルのバージョン管理に対応していないということです。

手動でCore Dataを利用する際、モデルの更新が不要であれば、『~.xcdatamodeld』グループを作成せずResource直下に『~.xcdatamodel』を置くことになると思いますが、その際に指定する拡張子は『momd』ではなく『mom』になることに注意してください。

詳細は『Cocoaの日々/[iOS][Mac] CoreData - マイグレーション[4] モデルファイルの構成』を参照してください。

特定したモデルファイルの場所のURLを用い、initWithContentsOfURL:メソッドでモデルを初期化して返します。

initWithContentsOfURL:

- (id)initWithContentsOfURL:(NSURL *)url

指定したURLにあるモデルファイルを使用してレシーバを初期化します。

戻り値は、urlにあるファイルを使用して初期化された管理オブジェクトモデルです。

url:モデルファイルの場所を指定するURLオブジェクトです。

5)persistentStoreCoordinatorの追加

persistentStoreCoordinatorはアプリケーション用の永続ストアコーディネータを返すメソッドで、コーディネータが存在しない場合は生成し、アプリケーションのストアに追加します。

最初にコーディネータのインスタンス変数persistentStoreCoordinator_の存在の有無を判別し、あればそのままモデルを返します。

コーディネータが無い場合、まず後述するapplicationDocumentsDirectoryメソッドでアプリケーションのDocumentsディレクトリを特定し、URLByAppendingPathComponent:メソッドで永続ストアファイル『Core_Data_Persistence.sqlite』が置かれている場所のURLを取得します。

次にinitWithManagedObjectModel:メソッドを用い、前述のmanagedObjectModelメソッドで得られる管理オブジェクトモデルで、コーディネータを生成・初期化します。

addPersistentStoreWithType:configuration:URL:options:error:メソッドで、特定した永続ストアファイルの場所にNSSQLiteStoreTypeの永続ストアを追加し、新たな永続ストアが生成されたらコーディネータを返し、生成に失敗した場合はNSLogでエラーを返してabort()で異常終了します。

initWithManagedObjectModel:

- (id)initWithManagedObjectModel:(NSManagedObjectModel *)model

管理オブジェクトモデルを含むレシーバを初期化します。

戻り値はmodelを含む初期化されたレシーバです。

model:管理オブジェクトモデルを指定します。

addPersistentStoreWithType:configuration:URL:options:error:

- (NSPersistentStore *)addPersistentStoreWithType:(NSString *)storeType configuration:(NSString *)configuration URL:(NSURL *)storeURL options:(NSDictionary *)options error:(NSError **)error

指定した場所にある指定した型の新しい永続ストアを追加し、新しいストアを返します。

戻り値は新しく生成されたストア、またはエラーが発生した場合はnilを返します。

storeType:ストア型を指定する文字列定数(例えばNSSQLiteStoreTypeなど)を指定します。
(可能な値は『Store Types』を参照してください)

configuration:新しいストアによって使用される、レシーバの管理オブジェクトモデル内の構成の名前を指定します。

storeURL:永続ストアのファイルの場所を指定します。

options:ストアを読み込みのみにするかどうかと、(XMLストアの場合は)読み込む前にXMLファイルがDTDに対して検証するかどうかを指定するキー値ペアを含む辞書を指定します。
キーの定義については『Store Options』と『Migration Options』を参照してください。
この値はnilの場合があります。

error:新しいストアが生成できない場合に、問題を説明するNSErrorのインスタンスを含めて返します。

Store Types

永続ストアの型です。

NSString * const NSSQLiteStoreType;
NSString * const NSBinaryStoreType;
NSString * const NSInMemoryStoreType;

NSSQLiteStoreType
SQLiteデータベースのストア型。

NSBinaryStoreType
バイナリのストア型。

NSInMemoryStoreType
インメモリのストア型。

6)applicationDocumentsDirectoryの追加

applicationDocumentsDirectoryは、アプリケーションのドキュメントディレクトリへのURLを返すメソッドです。

defaultManagerメソッドでシステムのファイルマネージャを取得し、URLsForDirectory:inDomains:メソッドを用いて、ユーザのホームディレクトリ(NSUserDomainMask)にあるドキュメントディレクトリ(NSDocumentDirectory)を検索し、検索結果をURLの配列で返します。

iOSの場合、アプリケーション自身のディレクトリ以外にアクセスできませんし、ドキュメントディレクトリも一つしか持たないので検索結果(の配列要素数)は一つだと思われますが、取得にはlastObjectメソッドを使用しています。

defaultManager

+ (NSFileManager *)defaultManager

ファイルシステムのデフォルトNSFileManagerオブジェクトを返します。

常にファイルマネージャの同じインスタンスを返します。

このオブジェクトはスレッドセーフではありません。

URLsForDirectory:inDomains:

- (NSArray *)URLsForDirectory:(NSSearchPathDirectory)directory inDomains:(NSSearchPathDomainMask)domainMask

要求された場所内にある指定された共有ディレクトリのURLの配列を返します。

戻り値は検索された順番のディレクトリを含むURLの配列です。

このメソッドは、システム内の既知な共有ディレクトリの場所を決定することを意図しています。

例えば、NSApplicationDirectoryへのディレクトリを設定すると、要求された場所内のアプリケーションディレクトリを返します。

NSSearchPathDirectoryで利用できる共有ディレクトリには、NSDesktopDirectoryNSApplicationSupportDirectoryなど多数あります。

directory:検索パスのディレクトリを指定します。
サポートされる値はNSSearchPathDirectoryで説明されています。

domainMask:検索を行う場所を指定します。
定数はNSSearchPathDomainMaskで指定されています。



参考文献

iOS Core Dataチュートリアル

Programming Place Plus/C言語編 第65章 終了関数

Cocoaの日々/[iOS][Mac] CoreData - マイグレーション[4] モデルファイルの構成

詳解 Objective-C 2.0 第3版詳解 Objective-C 2.0 第3版
(2011/12/28)
荻原 剛志

商品詳細を見る

はじめてのiPhone3プログラミングはじめてのiPhone3プログラミング
(2009/12/17)
Dave Mark、Jeff LaMarche 他

商品詳細を見る

Beginning Ios 6 Development: Exploring the Ios SdkBeginning Ios 6 Development: Exploring the Ios Sdk
(2012/12/26)
David Mark、Jack Nutting 他

商品詳細を見る






Lifestyle 650 home entertainment system
0 Comments
Leave a comment
管理者にだけ表示を許可する
Top
0 Trackbacks
Top
Calendar
10 | 2017/11 | 12
Sun Mon Tue Wed Thu Fri Sat
- - - 1 2 3 4
5 6 7 8 9 10 11
12 13 14 15 16 17 18
19 20 21 22 23 24 25
26 27 28 29 30 - -
Recent Articles
iTunes


Swift
Categories
Tips
Profile

水月杏香

Author:水月杏香
永遠の初心者プログラマ。

Wish List
WACOM


ARC
Technical Q&A
情報プロパティリストキー
Start Developing iOS Apps Today
BOSE

Lifestyle 650 home entertainment system
Reference
NSApplicationDelegateプロトコル
NSArrayクラス
NSAutoreleasePoolクラス
NSBundleクラス
NSBundle UIKit追加分
NSCalendarクラス
NSCoderクラス
NSCodingプロトコル
NSCopyingプロトコル
NSDataクラス
NSDateクラス
NSDateFormatterクラス
NSDictionaryクラス
NSEntityDescriptionクラス
NSEnumeratorクラス
NSErrorクラス
NSExceptionクラス
NSFetchRequestクラス
NSFileHandleクラス
NSFileManagerクラス
NSIndexPathクラス
NSIndexPath UIKit追加分
NSKeyedArchiverクラス
NSKeyedUnarchiverクラス
NSKeyValueCodingプロトコル
NSLocaleクラス
NSManagedObjectクラス
NSManagedObjectContextクラス
NSManagedObjectModelクラス
NSMutableArrayクラス
NSMutableCopyingプロトコル
NSMutableDictionaryクラス
NSMutableSetクラス
NSNotificationクラス
NSNotificationCenterクラス
NSNullクラス
NSNumberクラス
NSObjectクラス
NSObject UIKit追加分
NSObjectプロトコル
NSPersistentStoreクラス
NSPersistentStoreCoordinatorクラス
NSPredicateクラス
NSPropertyListSerializationクラス
NSRunLoopクラス
NSSetクラス
NSStringクラス
NSString UIKit追加分
NSTimerクラス
NSTimeZoneクラス
NSURLクラス
NSURLProtectionSpaceクラス
NSURLRequestクラス
NSUserDefaultsクラス
NSValueクラス

UIActionSheetクラス
UIActionSheetDelegateプロトコル
UIActivityIndicatorViewクラス
UIAlertViewクラス
UIAlertViewDelegateプロトコル
UIApplicationクラス
UIApplicationDelegateプロトコル
UIBarButtonItemクラス
UIBarItemクラス
UIButtonクラス
UIColorクラス
UIControlクラス
UIDatePickerクラス
UIDeviceクラス
UIEventクラス
UIFontクラス
UIGestureRecognizerクラス
UIImageクラス
UIImageViewクラス
UIKit Function
UILabelクラス
UINavigationControllerクラス
UINavigationItemクラス
UIPickerViewクラス
UIPickerViewDataSourceプロトコル
UIPickerViewDelegateプロトコル
UIPinchGestureRecognizerクラス
UIResponderクラス
UIScreenクラス
UIScrollViewクラス
UISearchBarクラス
UISearchBarDelegateプロトコル
UISegmentedControlクラス
UISliderクラス
UISwipeGestureRecognizerクラス
UISwitchクラス
UITableViewクラス
UITableViewCellクラス
UITableViewControllerクラス
UITableViewDataSourceプロトコル
UITableViewDelegateプロトコル
UITapGestureRecognizerクラス
UITextFieldクラス
UITextFieldDelegateプロトコル
UITextInputTraitsプロトコル
UITextViewクラス
UITextViewDelegateプロトコル
UIToolbarクラス
UITouchクラス
UIViewクラス
UIViewControllerクラス
UIWebViewクラス
UIWebViewDelegateプロトコル
UIWindowクラス

AVAudioPlayerクラス
AVAudioPlayerDelegateプロトコル

CADisplayLinkクラス
CAEAGLLayerクラス
CALayerクラス

CGAffineTransform
CGBitmapContext
CGColor
CGColorSpace
CGContext
CGGeometry
CGImage
CGPath

EAGLContextクラス
EAGLDrawableプロトコル

Foundation Constants
Foundation Data Types
Foundation Functions

MPMediaItemクラス
MPMediaItemArtworkクラス
MPMediaPlaylistクラス
MPMediaPropertyPredicateクラス
MPMediaQueryクラス
MPMusicPlayerControllerクラス

Randomization Services

System Sound Services
Amazon


OpenGL ES
SQLite
Monthly Archives
Recent Comments
Recent TrackBacks
RSS Link
Visitors
QR Code
QR