Persistence(17)~Core Dataでの保存(4)

2011. 07. 25
●ビューコントローラのソースファイルPersistenceViewController.mの編集

ソースファイルでは、4つのテキストフィールドのプロパティの実装と、viewDidLoadメソッドでの永続ストアからテキストフィールドへ値を反映する機能の追加、そしてアプリケーションが非アクティブになる際にテキストフィールドの値を永続ストアへ保存するapplicationWillResignActive:メソッドの追加を行います。

#import "PersistenceViewController.h"

#import "Core_Data_PersistenceAppDelegate.h"


@implementation PersistenceViewController

@synthesize line1;
@synthesize line2;
@synthesize line3;
@synthesize line4;


// Implement viewDidLoad to do additional setup after loading the view, typically from a nib.

- (void)viewDidLoad {
    [super viewDidLoad];
    Core_Data_PersistenceAppDelegate *appDelegate = [[UIApplication sharedApplication] delegate];
    NSManagedObjectContext *context = [appDelegate managedObjectContext];
    NSEntityDescription *entityDescription = [NSEntityDescription entityForName:@"Line" inManagedObjectContext:context];
    NSFetchRequest *request = [[NSFetchRequest alloc] init];
    [request setEntity:entityDescription];

    NSError *error;
    NSArray *objects = [context executeFetchRequest:request error:&error];
    if (objects == nil) {
        NSLog(@"There was an error!");
        // Do whatever error handling is appropriate
    }

    for (NSManagedObject *oneObject in objects) {
        NSNumber *lineNum = [oneObject valueForKey:@"lineNum"];
        NSString *lineText = [oneObject valueForKey:@"lineText"];

        NSString *fieldName = [NSString stringWithFormat:@"line%d", [lineNum integerValue]];
        UITextField *theField = [self valueForKey:fieldName];
        theField.text = lineText;
    }
    [request release];

    UIApplication *app = [UIApplication sharedApplication];
    [[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(applicationWillResignActive:) name:UIApplicationWillResignActiveNotification object:app];

}

- (void)applicationWillResignActive:(NSNotification *)notification {
    Core_Data_PersistenceAppDelegate *appDelegate = [[UIApplication sharedApplication] delegate];
    NSManagedObjectContext *context = [appDelegate managedObjectContext];
    NSError *error;
    for (int i = 1; i <= 4; i++) {
        NSString *fieldName = [NSString stringWithFormat:@"line%d", i];
        UITextField *theField = [self valueForKey:fieldName];

        NSFetchRequest *request = [[NSFetchRequest alloc] init];

        NSEntityDescription *entityDescription = [NSEntityDescription entityForName:@"Line" inManagedObjectContext:context];
        [request setEntity:entityDescription];
        NSPredicate *pred = [NSPredicate predicateWithFormat:@"(lineNum = %d)", i];
        [request setPredicate:pred];

        NSManagedObject *theLine = nil;

        NSArray *objects = [context executeFetchRequest:request error:&error];

        if (objects == nil) {
            NSLog(@"There was an error!");
            // Do whatever error handling is appropriate
        }
        if ([objects count] > 0)
            theLine = [objects objectAtIndex:0];
        else
            theLine = [NSEntityDescription insertNewObjectForEntityForName:@"Line" inManagedObjectContext:context];

        [theLine setValue:[NSNumber numberWithInt:i] forKey:@"lineNum"];
        [theLine setValue:theField.text forKey:@"lineText"];

        [request release];
    }
    [context save:&error];
}


- (void)didReceiveMemoryWarning {
    // Releases the view if it doesn't have a superview.
    [super didReceiveMemoryWarning];

    // Release any cached data, images, etc. that aren't in use.
}

- (void)viewDidUnload {
    [super viewDidUnload];
    // Release any retained subviews of the main view.
    // e.g. self.myOutlet = nil;

    self.line1 = nil;
    self.line2 = nil;
    self.line3 = nil;
    self.line4 = nil;

}

- (void)dealloc {
    [line1 release];
    [line2 release];
    [line3 release];
    [line4 release];

    [super dealloc];
}

@end

7439

1)Core_Data_PersistenceAppDelegate.hのインポート

永続ストアとのデータの読み込み/書き込みを行うため、アプリケーションデリゲートのヘッダファイルをインポートしています。

2)4つのプロパティの実装

ヘッダファイルで宣言した4つのテキストフィールドのプロパティを実装します。

3)不要なメソッドの削除

initWithNibName:bundle:shouldAutorotateToInterfaceOrientation:メソッドは今回使用しないので削除しています。

4)viewDidLoadメソッドの編集

viewDidLoadメソッドでは、永続ストアから保存されているデータを読み込んでテキストフィールドに反映させる処理と、通知センターを作成してアプリケーションが非アクティブになる際にapplicationWillTerminate:メソッドを呼び出す処理を行っています。

実際の保存データの読み込みは、アプリケーションのインスタンスのデリゲートから管理オブジェクトコンテキストを取得し、フェッチ要求で管理オブジェクトとして保存されている内容を取得、高速列挙で内容をテキストフィールドに設定するという流れになっています。

まずsharedApplicationメソッドでアプリケーションのインスタンスを生成し、delegateプロパティでデリゲートappDelegateを取得します。

デリゲートからCore_Data_PersistenceAppDelegateクラスのmanagedObjectContextプロパティで管理オブジェクトコンテキストcontextを取得します。

そのコンテキストからentityForName:inManagedObjectContext:メソッドで名前が『Line』のエンティティを取得するためのエンティティ記述entityDescriptionを作成し、setEntity:メソッドでフェッチ要求requestとして設定します。

このフェッチ要求をコンテキストに対してexecuteFetchRequest:error:メソッドで実行し、エンティティ名Lineの管理オブジェクトを配列objectsとして取得します。

取得した管理オブジェクトの配列は、高速列挙でテキストフィールドに反映させます。

管理オブジェクトから、属性『lineNum』をキーとしてvalueForKey:メソッドで行番号lineNumを、属性『lineText』をキーとしてvalueForKey:メソッドで文字列lineTextを取得します。

行番号lineNumは、integerValueメソッドで整数値に変換し、stringWithFormat:メソッドでテキストフィールドのプロパティ名『line~』となるように合成されます。

合成された文字列fieldNameを用いて、valueForKey:メソッドで当該テキストフィールドのプロパティを取得し、textプロパティで管理オブジェクトから取り出した文字列lineTextを設定します。
(『Persistence(10)~SQLite3への保存(4)』の『2)viewDidLoadの編集』の項を参照)

最後にアプリケーションが非アクティブになる際にapplicationWillTerminate:メソッドを呼び出す仕掛けをします。

sharedApplicationメソッドで別のアプリケーションのインスタンスを生成し、defaultCenterメソッドで通知センターを用意し、addObserver:selector:name:object:メソッドで非アクティブの通知UIApplicationWillResignActiveNotificationがポストされた時にapplicationWillTerminate:メソッドを呼び出すように設定します。

entityForName:inManagedObjectContext:

+ (NSEntityDescription *)entityForName:(NSString *)entityName inManagedObjectContext:(NSManagedObjectContext *)context

指定した管理オブジェクトコンテキストの永続ストアコーディネータに関連付けされた管理オブジェクトモデルから、指定した名前のエンティティを返します。

このメソッドは以下のコード例と機能的に同等です。

NSManagedObjectModel *managedObjectModel = [[context persistentStoreCoordinator] managedObjectModel];
NSEntityDescription *entity = [[managedObjectModel entitiesByName] objectForKey:entityName];
return entity;

entityName:エンティティの名前を指定します。

context:使用する管理オブジェクトコンテキストを指定します。

setEntity:

- (void)setEntity:(NSEntityDescription *)entity

レシーバのエンティティを設定します。

entity:レシーバのエンティティを指定します。

executeFetchRequest:error:

- (NSArray *)executeFetchRequest:(NSFetchRequest *)request error:(NSError **)error

与えたフェッチ要求によって指定された基準を満たす、オブジェクトの配列を返します。

戻り値は、レシーバの永続ストアコーディネータに関連付けされた永続ストアから、レシーバからフェッチされた要求によって指定された基準を満たすオブジェクトです。

エラーが発生した場合はnilを返します。

リクエストで指定された基準に一致するオブジェクトが無かった場合は、空の配列を返します。

返されたオブジェクトは、レシーバに登録されます。

考慮すべき重要な点は以下の通りです。

  • フェッチ要求に述語が無い場合、指定されたエンティティの全てのインスタンスを取得し、以下の基準に従います。

  • (リクエストによって指定されたエンティティのインスタンスで、もしあるならリクエストの述語と一致する)requestによって指定された基準を満たし、コンテキストに挿入されているが永続ストアにまだ保存されていないオブジェクトは、フェッチ要求がコンテキスト上で実行された場合に取得されます。

  • コンテキスト内のオブジェクトが変更されている場合、永続ストア内の現在の状態に対してではなく、述語は変更された状態と比較して評価します。
    したがって、コンテキスト内のオブジェクトがフェッチ要求の基準を満たすように変更されていた場合、リクエストはたとえ変更がストアに保存されていない場合でも、基準を満たしていないストア内の値を取得します。
    逆に、コンテキスト内のオブジェクトがフェッチ要求と一致しないように変更されていた場合、フェッチ要求はストア内のバージョンと一致していても取得しません。

  • オブジェクトがコンテキストから削除されている場合、フェッチ要求はたとえその削除がストアに保存されていなくても、取得しません。
更新の保留や挿入、削除だけでなく、(populated、faults fired、『read from』など)実体化されたオブジェクトは、開発者の介入無しにフェッチ操作によって変更されることはありません。

いくつかのオブジェクトをフェッチする場合は、それらを一緒に処理し、新しいインスタンスの取得または既存のオブジェクトのデータ更新はしないで(現在のインメモリの状態を持つ既存のオブジェクトを取得し)、それからそれらのオブジェクトのスーパーセットを含む新しいフェッチを実行してください。

request:フェッチの検索基準を指定するフェッチ要求を指定します。

error:フェッチを実行して問題があった場合、問題を説明するNSErrorのインスタンスを含めて返します。

5)applicationWillTerminate:メソッドの追加

applicationWillTerminate:メソッドはviewDidLoadと逆の手順で、アプリケーションが非アクティブになる際に、テキストフィールドに入力されている文字列を管理オブジェクトに設定し、フェッチ要求で管理オブジェクトコンテキストを通して永続ストアに保存する処理を行っています。

最初にviewDidLoadと同様に、アプリケーションのインスタンスとデリゲートを準備し、管理オブジェクトコンテキストのインスタンスcontextを取得します。

次にforループで4つのテキストフィールドを1行ずつ処理します。

stringWithFormat:メソッドでテキストフィールドのプロパティ名を作成し、valueForKey:メソッドでプロパティを取得します。

コンテキストからentityForName:inManagedObjectContext:メソッドで名前が『Line』のエンティティを取得するためのエンティティ記述entityDescriptionを作成し、setEntity:メソッドでフェッチ要求requestとして設定します。

そしてpredicateWithFormat:メソッドで行番号を指定する述語を生成し、setPredicate:メソッドで述語を設定して、Lineエンティティから当該行だけを抽出します。

このフェッチ要求をコンテキストに対してexecuteFetchRequest:error:メソッドで実行し、エンティティ名Lineの管理オブジェクトを配列objectsとして取得します。

管理オブジェクトの配列objectsがnil、つまりLineエンティティが無かった場合はNSLogでエラーを出力します。
(本来は適切なエラー処理を行う必要があります)

配列objectsの要素数が0より上の場合、つまり既に永続ストアに当該行のデータが保存されていた場合は、objectAtIndex:メソッドで配列のインデックス0の要素を管理オブジェクトtheLineに設定します。

要素数が0の場合、つまり永続ストアに当該行のデータが無かった場合は、insertNewObjectForEntityForName:inManagedObjectContext:メソッドでエンティティ名Lineの管理オブジェクトを新規に生成してtheLineに設定します。

後は管理オブジェクトtheLineにsetValue:forKey:メソッドを用いて、テキストフィールドの行番号lineNumと文字列lineTextを設定します。

全てのテキストフィールドに対して管理オブジェクトの設定が終わったら、save:メソッドで未保存の変更を永続ストアに保存します。

predicateWithFormat:

+ (NSPredicate *)predicateWithFormat:(NSString *)format...

指定したフォーマットで新しい文字列を生成し、解析した結果によって構成された新しい述語を生成して返します。

フォーマット文字列の書式と変数の代入での制限の詳細については、『Predicate Format String Syntax』を参照してください。

format:新しい述語のためのフォーマット文字列を指定します。

...:formatに代入する引数をコンマ区切りのリストで指定します。

setPredicate:

- (void)setPredicate:(NSPredicate *)predicate

レシーバの述語を設定します。

predicate:レシーバの述語を指定します。

insertNewObjectForEntityForName:inManagedObjectContext:

+ (id)insertNewObjectForEntityForName:(NSString *)entityName inManagedObjectContext:(NSManagedObjectContext *)context

指定した名前でエンティティのクラスのインスタンスを生成、構成をして返します。

戻り値は、entityNameで名付けられたエンティティのクラスのインスタンスを、新規に完全に構成して自動解放します。

インスタンスはエンティティ記述のセットを持ち、contextに挿入されます。

このメソッドは、管理オブジェクトの生成の詳細について心配すること無く、指定したエンティティのインスタンスを簡単に生成することができます。

メソッドはMac OS X v10.4で特に役立ち、エンティティを表すために使用するクラスを知らなくても、新規に管理オブジェクトの生成に使用することができます。

これはクラスとクラス名が揮発性の場合、初期の開発ライフサイクルにおいて特に有効です。

メソッドは、以下のコード例と概念的に類似しています。

NSManagedObjectModel *managedObjectModel = [[context persistentStoreCoordinator] managedObjectModel];
NSEntityDescription *entity = [[managedObjectModel entitiesByName] objectForKey:entityName];
NSString *className = [entity managedObjectClassName];
Class entityClass = [[NSBundle mainBundle] classNamed:className];
id newObject = [[entityClass alloc] initWithEntity:entity insertIntoManagedObjectContext:context];
return [newObject autorelease];

Mac OS X v10.5以降とiOSでは、エンティティのための適切なクラスのインスタンスを返す際に、initWithEntity:insertIntoManagedObjectContext:の代わりに使用することができます。

Mac OS X v10.5とiOSの同等なコードは以下のようになります。

NSManagedObjectModel *managedObjectModel = [[context persistentStoreCoordinator] managedObjectModel];
NSEntityDescription *entity = [[managedObjectModel entitiesByName] objectForKey:entityName];
NSManagedObject *newObject = [[NSManagedObject alloc] initWithEntity:entity insertIntoManagedObjectContext:context];
return [newObject autorelease];

重要:メソッド名に『new』という言葉が存在しますが、参照カウントの環境において、返されたオブジェクトを解放する責任はありません。
(『new』がメソッド名の最初の言葉ではないからで、『Memory Management Rules』を参照してください)

entityName:エンティティの名前を指定します。

context:使用する管理オブジェクトコンテキストを指定します。


●アプリケーションデリゲートのソースファイルCore_Data_PersistenceAppDelegate.mの編集

ウィンドウにビューを追加します。
(太字が追加した部分)

#import "Core_Data_PersistenceAppDelegate.h"
#import "PersistenceViewController.h"

@implementation Core_Data_PersistenceAppDelegate

@synthesize window;
@synthesize rootController;

#pragma mark -
#pragma mark Application lifecycle

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

    // Override point for customization after application launch.
    [self.window addSubview:rootController.view];
    [self.window makeKeyAndVisible];

    return YES;
}

7436

1)ビューコントローラのインポート

ビューを追加するため、ビューコントローラPersistenceViewController.hをインポートします。

2)プロパティの実装

ビューコントローラのプロパティrootControllerを実装します。

3)ウィンドウへのビューの追加

addSubview:メソッドで、ウィンドウにビューコントローラのビューを追加します。


●ビルドと実行

編集が終わったら『ビルドと実行』を行い、動作を確認します。

7441



参考文献

iOS Core Dataチュートリアル

はじめての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 他

商品詳細を見る






QuietControl 30 wireless headphones
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

QuietControl 30 wireless headphones
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