プロジェクトを作った後にCoreDataを追加する方法

普通はアプリを作成する際にCoreDataを使うにチェックを入れておくけど、チェックを入れてなかったプロジェクトに後でCoreDataを追加したい手順を書いておく。

1. Data Model追加

  • Xcodeのメニューから File > New > New File... を選択。
  • テンプレート選択ウインドウで iOS > Core Data > Data Model を選択。
  • xcdatamodelファイルを保存

2. Entity追加

  • 追加されたxcdatamodelファイルを選択。
  • Add EntityをクリックしてEntityを追加
  • 追加したEntityにAttibutesを追加、定義
  • 作成したEntityを選択して、Editor -> CreateNSManagedObjectSubClassでEntityに対応したソースを作成する

3. データファイル保存用のDirectoryを作成

  • SQLiteの場合データファイル配置用のディレクトリがないとエラーになるのでディレクトリを作成しておく デフォルトは/Users/AirMyac/Library/Application Support/${HOGE}
    ※最初からCoreData作っても必要だと思う

  • 配布するなら起動時とかに作っとかないといけないから適当なコードで作成するようにしておく

こんな感じ?

- (void)applicationDidFinishLaunching:(NSNotification *)aNotification
{
    NSURL *applicationFilesDirectory = [self applicationFilesDirectory];
    NSError *error = nil;
    if(![[NSFileManager defaultManager] createDirectoryAtPath:[applicationFilesDirectory path] withIntermediateDirectories:YES attributes:nil error:&error]){
        NSLog(@"Couldn't create the data store directory.[%@, %@]", error, [error userInfo]);
        abort();
    }
}

4. AppDelegate.hに必要なソースを追記

自動生成される必要なソースを追記する。

@property (readonly, strong, nonatomic) NSPersistentStoreCoordinator *persistentStoreCoordinator;
@property (readonly, strong, nonatomic) NSManagedObjectModel *managedObjectModel;
@property (readonly, strong, nonatomic) NSManagedObjectContext *managedObjectContext;

5. AppDelegate.mにも必要なソースを追記

@synthesize persistentStoreCoordinator = _persistentStoreCoordinator;
@synthesize managedObjectModel = _managedObjectModel;
@synthesize managedObjectContext = _managedObjectContext;

- (void)applicationDidFinishLaunching:(NSNotification *)aNotification
    {
        // Insert code here to initialize your application
        // 初回起動用にDataStore用のDirectoryを作成する
        NSURL *applicationFilesDirectory = [self applicationFilesDirectory];
        NSError *error = nil;
        if(![[NSFileManager defaultManager] createDirectoryAtPath:[applicationFilesDirectory path] withIntermediateDirectories:YES attributes:nil error:&error]){
            NSLog(@"Couldn't create the data store directory.[%@, %@]", error, [error userInfo]);
            abort();
        }
    }

    // Returns the directory the application uses to store the Core Data store file. This code uses a directory named hoge" in the user's Application Support directory.
    - (NSURL *)applicationFilesDirectory
    {
        NSFileManager *fileManager = [NSFileManager defaultManager];
        NSURL *appSupportURL = [[fileManager URLsForDirectory:NSApplicationSupportDirectory inDomains:NSUserDomainMask] lastObject];
        return [appSupportURL URLByAppendingPathComponent:@"Hoge"];
    }

    // Creates if necessary and returns the managed object model for the application.
    - (NSManagedObjectModel *)managedObjectModel
    {
        if (_managedObjectModel) {
            return _managedObjectModel;
        }

        NSURL *modelURL = [[NSBundle mainBundle] URLForResource:@"Model" withExtension:@"momd"];
        _managedObjectModel = [[NSManagedObjectModel alloc] initWithContentsOfURL:modelURL];
        return _managedObjectModel;
    }

    // Returns the persistent store coordinator for the application. This implementation creates and return a coordinator, having added the store for the application to it. (The directory for the store is created, if necessary.)
    - (NSPersistentStoreCoordinator *)persistentStoreCoordinator
    {
        if (_persistentStoreCoordinator) {
            return _persistentStoreCoordinator;
        }

        NSManagedObjectModel *mom = [self managedObjectModel];
        if (!mom) {
            NSLog(@"%@:%@ No model to generate a store from", [self class], NSStringFromSelector(_cmd));
            return nil;
        }

        NSURL *applicationFilesDirectory = [self applicationFilesDirectory];
        NSError *error = nil;
        NSURL *url = [applicationFilesDirectory URLByAppendingPathComponent:@"hoge.sqlite"];
        NSPersistentStoreCoordinator *coordinator = [[NSPersistentStoreCoordinator alloc] initWithManagedObjectModel:mom];
        if (![coordinator addPersistentStoreWithType:NSSQLiteStoreType configuration:nil URL:url options:nil error:&error]) {
            NSLog(@"Unresolved error %@, %@", error, [error userInfo]);
            abort();
        }

        _persistentStoreCoordinator = coordinator;
        return _persistentStoreCoordinator;
    }

    // Returns the managed object context for the application (which is already bound to the persistent store coordinator for the application.)
    - (NSManagedObjectContext *)managedObjectContext
    {
        if (_managedObjectContext) {
            return _managedObjectContext;
        }

        NSPersistentStoreCoordinator *coordinator = [self persistentStoreCoordinator];
        if (!coordinator) {
            NSMutableDictionary *dict = [NSMutableDictionary dictionary];
            [dict setValue:@"Failed to initialize the store" forKey:NSLocalizedDescriptionKey];
            [dict setValue:@"There was an error building up the data file." forKey:NSLocalizedFailureReasonErrorKey];
            NSError *error = [NSError errorWithDomain:@"YOUR_ERROR_DOMAIN" code:9999 userInfo:dict];
            [[NSApplication sharedApplication] presentError:error];
            return nil;
        }
        _managedObjectContext = [[NSManagedObjectContext alloc] init];
        [_managedObjectContext setPersistentStoreCoordinator:coordinator];

        return _managedObjectContext;
    }

    // Returns the NSUndoManager for the application. In this case, the manager returned is that of the managed object context for the application.
    - (NSUndoManager *)windowWillReturnUndoManager:(NSWindow *)window
    {
        return [[self managedObjectContext] undoManager];
    }

    // Performs the save action for the application, which is to send the save: message to the application's managed object context. Any encountered errors are presented to the user.
    - (IBAction)saveAction:(id)sender
    {
        NSError *error = nil;
        if (![[self managedObjectContext] commitEditing]) {
            NSLog(@"%@:%@ unable to commit editing before saving", [self class], NSStringFromSelector(_cmd));
        }
        if (![[self managedObjectContext] save:&error]) {
            [[NSApplication sharedApplication] presentError:error];
        }
    }

    - (NSApplicationTerminateReply)applicationShouldTerminate:(NSApplication *)sender
    {
        // Save changes in the application's managed object context before the application terminates.
        if (!_managedObjectContext) {
            return NSTerminateNow;
        }
        if (![[self managedObjectContext] commitEditing]) {
            NSLog(@"%@:%@ unable to commit editing to terminate", [self class], NSStringFromSelector(_cmd));
            return NSTerminateCancel;
        }
        if (![[self managedObjectContext] hasChanges]) {
            return NSTerminateNow;
        }

        NSError *error = nil;
        if (![[self managedObjectContext] save:&error]) {
            // Customize this code block to include application-specific recovery steps.
            BOOL result = [sender presentError:error];
            if (result) {
                return NSTerminateCancel;
            }
            NSString *question = NSLocalizedString(@"Could not save changes while quitting. Quit anyway?", @"Quit without saves error question message");
            NSString *info = NSLocalizedString(@"Quitting now will lose any changes you have made since the last successful save", @"Quit without saves error question info");
            NSString *quitButton = NSLocalizedString(@"Quit anyway", @"Quit anyway button title");
            NSString *cancelButton = NSLocalizedString(@"Cancel", @"Cancel button title");
            NSAlert *alert = [[NSAlert alloc] init];
            [alert setMessageText:question];
            [alert setInformativeText:info];
            [alert addButtonWithTitle:quitButton];
            [alert addButtonWithTitle:cancelButton];

            NSInteger answer = [alert runModal];

            if (answer == NSAlertAlternateReturn) {
                return NSTerminateCancel;
            }
        }
        return NSTerminateNow;
    }

  }