26

I started off the project without Core Data and now I would like to add that functionality to my apps. How do I do this?

What additional things does XCode sets up when you actually tick the Use Core Data when you create a new project?

Monolo
  • 18,205
  • 17
  • 69
  • 103
adit
  • 32,574
  • 72
  • 229
  • 373
  • 1
    possible duplicate of [Adding Core Data to existing iPhone project](http://stackoverflow.com/questions/2032818/adding-core-data-to-existing-iphone-project) – Michael Dautermann May 29 '12 at 01:37

6 Answers6

42

One trick is to just create a new empty project with Core Data support. That will give you the necessary code that you can copy over to your original project and compile.

The only gotcha is that you need to handle the Core Data header file. Xcode puts it in the precompiled header files when it generates files using the templates. So you can add the following line to your .pch file:

#import <CoreData/CoreData.h>

or you can just add it to the .m files where needed.

It works like a charm. Notice Luka's comment below about how to do it in Xcode5.

Monolo
  • 18,205
  • 17
  • 69
  • 103
  • I was actually going to do this, however I had a bunch of frameworks linked in (three20, etc) – adit Jul 25 '11 at 21:17
  • 2
    Sorry if I wasn't clear - the idea is to copy the useful code over from a vanilla template generated by Xcode just for that purpose. You maintain all of your existing Xcode project. – Monolo Jul 25 '11 at 21:39
  • so from xcode generated template to my existing project not the other way around – adit Jul 25 '11 at 22:16
  • Yup - and since it could very easily be misunderstood, I have edited the answer. Thanks for the heads-up. – Monolo Jul 25 '11 at 22:22
  • 2
    I thought it might help people to know that the "Use Core Data" option is not available in the Single View Based Application template in Xcode. You have to choose Empty Application instead. – Shea Daniels Dec 02 '11 at 05:09
  • 2
    Don't forget to add the CoreData framework in. Xcode 4.6: In project navigator click your project, your app in Targets, Summary tab, plus sign in Linked Frameworks and Libraries. – abc123 Mar 16 '13 at 16:49
  • And change the string names in `- (NSPersistentStoreCoordinator *)persistentStoreCoordinator` and `- (NSManagedObjectModel *)managedObjectModel` – abc123 Mar 16 '13 at 17:09
  • @SKG Thanks for pointing out the need to link the framework. I don't know what you mean about changing the string names, though. I searched for those names in my project and nothing looked fishy. Could you clarify? – mkc842 Jul 17 '13 at 00:27
  • 1
    In Xcode 5.0 you can select the "Master-Detail Application" or "Empty Application" template in order to get the "Use Core Data" option, and have the Core Data code generated. – lgdev Oct 11 '13 at 11:05
19

Just to expound on all the steps you actually need to perform to add Core Data to a project that previously did not have it:

Step 1: Add the Framework

Click on your app target (on the left pane its the top icon with the name of your app) then go to the 'Build Phases' tab then on 'Link Binary With Libraries', click the little '+' at the bottom then find 'CoreData.framework' and add it to your project

Then either import coredata on all the objects you need it (the non-sexy way) using:

#import <CoreData/CoreData.h>

or add the import below the common imports in your .pch file (much more sexy) like this:

#ifdef __OBJC__
    #import <UIKit/UIKit.h>
    #import <Foundation/Foundation.h>
    #import <CoreData/CoreData.h>
#endif

Step 2: Add the Data Model

To add the .xcdatamodel file right click/control-click on your files in the right pane (like in a Resources folder for safe keeping) and select to Add a New File, Click the Core Data tab when selecting your file type then Click 'Data Model', give it a name and click Next and Finish and it will add it to your project. When you click on this Model object you will see the interface to add the Entities to your project with any relationships you want.

Step 3: Update App Delegate

Add these objects to AppDelegate.h

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

 - (NSURL *)applicationDocumentsDirectory; // nice to have to reference files for core data

Synthesize the previous objects in AppDelegate.m like this:

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

Then add these methods to AppDelegate.m (make sure to put the name of the model that you added in the spots shown):

- (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();
        }
    }
}

- (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:@"NAMEOFYOURMODELHERE" withExtension:@"momd"];
    _managedObjectModel = [[NSManagedObjectModel alloc] initWithContentsOfURL:modelURL];
    return _managedObjectModel;
}

- (NSPersistentStoreCoordinator *)persistentStoreCoordinator
{
    if (_persistentStoreCoordinator != nil) {
        return _persistentStoreCoordinator;
    }

    NSURL *storeURL = [[self applicationDocumentsDirectory] URLByAppendingPathComponent:@"NAMEOFYOURMODELHERE.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 - Application's Documents directory

// Returns the URL to the application's Documents directory.
- (NSURL *)applicationDocumentsDirectory{
    return [[[NSFileManager defaultManager] URLsForDirectory:NSDocumentDirectory inDomains:NSUserDomainMask] lastObject];
}

Step 4: Get the Data Objects to the ViewControllers Where You Need the Data

in the ViewController.h

@property (nonatomic, retain) NSManagedObjectContext *managedObjectContext;

In the ViewController.m

@synthesize managedObjectContext = _managedObjectContext;

In the AppDelegate, or class where the ViewController is created set the managedObjectContext to be the same as the AppDelegate one

ViewController.managedObjectContext = self.managedObjectContext;

If you want the viewcontroller using Core Data to be a FetchedResultsController then you'll need to make sure this stuff is in your ViewController.h

@interface ViewController : UIViewController <NSFetchedResultsControllerDelegate> {
  NSFetchedResultsController *fetchedResultsController;
  NSManagedObjectContext *managedObjectContext;
}

 @property (nonatomic, retain) NSFetchedResultsController *fetchedResultsController;

And this is in ViewController.m

@synthesize fetchedResultsController, managedObjectContext;

After all of that you can now use this managedObjectContext to run all the usual fetchRequests needed for CoreData goodness! Enjoy

Peng90
  • 300
  • 2
  • 9
Chris Klingler
  • 5,258
  • 2
  • 37
  • 43
  • Great answer, one thing to notice is in the appDelegate header file, the method `- (NSString *)applicationDocumentsDirectory;` should be `- (NSURL *)applicationDocumentsDirectory;`. Otherwise it won't match the code in `- (NSPersistentStoreCoordinator *)persistentStoreCoordinator`. I've edited the answer with updated code. – Peng90 Apr 25 '14 at 16:10
  • 1
    Thank you for these complete instructions. This should be the correct answer. – SushiGrass Jacob Jul 08 '14 at 15:16
2

If you want to add CoreData.framework to your project, double-click the Target in your Groups and Files list. Go to the Summary pane, and click the "+" for Linked Libraries. Choose CoreData.framework. It will then link with your project.

Cody A. Ray
  • 5,869
  • 1
  • 37
  • 31
1

Xcode adds a bundle of stuff into the standard template for Core Data.

If you are not familiar with it then create a new Core Data project and push your own stuff into it rather than trying to add the infrastructure to your existing project.

Basically what you get is...

  • An empty Core Data model.
  • Init code for the Core Data stack
Warren Burton
  • 17,451
  • 3
  • 53
  • 73
  • Depends if you are using Document architecture or a simple view based app. You probably get some info.plist setup too. Spawn one and have a poke around. – Warren Burton Jul 25 '11 at 21:39
0

I've found the easiest way was to create a new project, with core data, delete the files in the project and drag and drop from the non-core data project to the core data project. (Main.storyboard, AppDelegate, ViewController, etc)

Luke
  • 1
0

It's really simple to add Core Data to your project by comparing it with a new project incl. Core Data. You need to add a "Data Model" file and some methods and ivars in the AppDelegate.

Look at the Core Data Project Template in the implementation file -> "Core Data stack".

Florian Mielke
  • 3,310
  • 27
  • 31