Any way to pre populate core data?

41,417

Solution 1

Here's the best way (and doesn't require SQL knowledge):
Create a quick Core Data iPhone app (Or even Mac app) using the same object model as your List app. Write a few lines of code to save the default managed objects you want to the store. Then, run that app in the simulator. Now, go to ~/Library/Application Support/iPhone Simulator/User/Applications. Find your application among the GUIDs, then just copy the sqlite store out into your List app's project folder.

Then, load that store like they do in the CoreDataBooks example.

Solution 2

Yes there is in fact the CoreDataBooks example does this, you can download the code here: sample code

What you do is create the internal store (database) using the normal procedure to initialize your store just like you would with any other store, then you simply run your code and let it execute the code as described in the CoreDataBooks example (code snippet below). Once the store has been initialized you will want to create a NSManagedObjectContext and initialize it with the created persistent store, insert all the entities you need, and save the context.

Once the context has been successfully saved, you can stop your application, then go to finder and go to folder: ~/Library/Developer type in the search .sqlite and look under /Developer, sorting by date will give you the most recent .sqlite database which should match the time that the code was executed, you can then take this store and add it as a resource of your project. This file then can be read by a persistent store coordinator.

- (NSPersistentStoreCoordinator *)persistentStoreCoordinator {

if (persistentStoreCoordinator) {
    return persistentStoreCoordinator;
}


NSString *storePath = [[self applicationDocumentsDirectory]      stringByAppendingPathComponent: @"CoreDataBooks.sqlite"];
 /*
  Set up the store.
 For the sake of illustration, provide a pre-populated default store.
 */
NSFileManager *fileManager = [NSFileManager defaultManager];
// If the expected store doesn't exist, copy the default store.
if (![fileManager fileExistsAtPath:storePath]) {
  NSString *defaultStorePath = [[NSBundle mainBundle] pathForResource:@"CoreDataBooks"      ofType:@"sqlite"];
 if (defaultStorePath) {
 [fileManager copyItemAtPath:defaultStorePath toPath:storePath error:NULL];
 }
}

NSURL *storeUrl = [NSURL fileURLWithPath:storePath];

 NSDictionary *options = [NSDictionary dictionaryWithObjectsAndKeys:[NSNumber   numberWithBool:YES], NSMigratePersistentStoresAutomaticallyOption, [NSNumber numberWithBool:YES], NSInferMappingModelAutomaticallyOption, nil]; 
  persistentStoreCoordinator = [[NSPersistentStoreCoordinator alloc] initWithManagedObjectModel: [self managedObjectModel]];

 NSError *error;
 if (![persistentStoreCoordinator addPersistentStoreWithType:NSSQLiteStoreType configuration:nil URL:storeUrl options:options error:&error]) {
  // Update to handle the error appropriately.
  NSLog(@"Unresolved error %@, %@", error, [error userInfo]);
 exit(-1);  // Fail
}    

return persistentStoreCoordinator;
}

Hope that helps.

-Oscar

Solution 3

With this method you don't need to make a separate app or have any SQL knowledge. You only need to be able to make a JSON file for your initial data.

I use a JSON file that I parse into objects, then insert them in Core Data. I do this when the app initializes. I also make one entity in my core data that indicates if this initial data is already inserted, after I insert the initial data I set this entity so the next time the script runs it sees that the initial data has already been initialized.

To read json file into objects:

NSString *initialDataFile = [[NSBundle mainBundle] pathForResource:@"InitialData" ofType:@"json"];
NSError *readJsonError = nil;
NSArray *initialData = [NSJSONSerialization
                        JSONObjectWithData:[NSData dataWithContentsOfFile:initialDataFile]
                        options:kNilOptions
                        error:&readJsonError];

if(!initialData) {
    NSLog(@"Could not read JSON file: %@", readJsonError);
    abort();
}

Then you can make entity objects for it like this:

[initialData enumerateObjectsUsingBlock:^(id objData, NSUInteger idx, BOOL *stop) {

    MyEntityObject *obj = [NSEntityDescription
                          insertNewObjectForEntityForName:@"MyEntity"
                          inManagedObjectContext:dataController.managedObjectContext];

    obj.name = [objData objectForKey:@"name"];
    obj.description = [objData objectForKey:@"description"];

    // then insert 'obj' into Core Data

}];

If you want a more detailed description on how to do this, check out this tutorial: http://www.raywenderlich.com/12170/core-data-tutorial-how-to-preloadimport-existing-data-updated

Solution 4

For 10 items, you can just do this within applicationDidFinishLaunching: in your app delegate.

Define a method, say insertPredefinedObjects, that creates and populates the instances of the entity in charge of managing your airport items, and save your context. You may either read the attributes from a file or simply hardwire them in your code. Then, call this method inside applicationDidFinishLaunching:.

Solution 5

Bear in mind, when following the CoreDataBooks example code, that it probably breaks the iOS Data Storage Guidelines:

https://developer.apple.com/icloud/documentation/data-storage/

I've had an app rejected for copying the (read-only) pre-populated database to the documents directory - as it then gets backed up to iCloud - and Apple only want that to happen to user-generated files.

The guidelines above offer some solutions, but they mostly boil down to:

  • store the DB in the caches directory, and gracefully handle situations where the OS purges the caches - you will have to rebuild the DB, which probably rules it out for most of us.

  • set a 'do not cache attribute' on the DB file, which is a little arcane, as it needs to be done differently for different OS versions.

I don't think it is too tricky, but be aware that you have a bit extra to do to make that example code work alongside iCloud...

Share:
41,417
Tanner
Author by

Tanner

Updated on July 05, 2022

Comments

  • Tanner
    Tanner almost 2 years

    I've been creating a list app and backing it with core data.

    I would like to have a default list of say 10 airport's items, so that the user doesn't have to start from scratch.

    Is there any way to do this?

    Any help is appreciated. Thanks in advance.

  • Oscar Gomez
    Oscar Gomez about 14 years
    No you don't I created mine just like you would create it using SQL Server 2005 and simply inserting the values, using SQLite Database Browser which you can get here: mac.softpedia.com/get/Developer-Tools/…
  • Tanner
    Tanner about 14 years
    I believe I would like the sql browser approach better because I could add different list. Ive downloaded it. Do I just add an item, name it passport and add 9 more items and then im done?
  • Oscar Gomez
    Oscar Gomez about 14 years
    Yes pretty much, it is as easy to use as any other Database browser.
  • Tanner
    Tanner about 14 years
    Ive never used sql before. If there all small words (passport, book) for file type would I choose text? Thanks
  • Tanner
    Tanner about 14 years
    Ive created a table named AirportTable. I then hit create but it said no fields were there so I made 1 field called passport. Is this all id have to do if I only want 1?
  • Tanner
    Tanner about 14 years
    I did the above then added a new record named "passport" saved it, then added it to the project with the code above however nothing happened
  • Oscar Gomez
    Oscar Gomez about 14 years
    Yes that is all you need. How are you displaying your results?, are you using a NSFetchedResultsController?, I assume the code posted and your table name match, it this correct?
  • Tanner
    Tanner about 14 years
    Yes but it made the app crash saying it excited with a sqlite error.
  • Brad Larson
    Brad Larson about 14 years
    This answer is misleading. You can't just dump data into any old SQLite database and then load it into Core Data. Core Data has a very specific internal structure to its SQLite databases that is not documented and that you are advised not to manually write to.
  • Tanner
    Tanner about 14 years
    Right, on opening the coredatabooks .sqlite there are many tables. Do you know of a way to make 10 items or a default list appear? Having the app ship with a blank list doesnt seem very attractive.
  • Tanner
    Tanner about 14 years
    If I do create a mac core data model and populate it, drag it over to my iphone project will it hold the list? Is this a way to go? Id rather not learn xml or such if this works. Please advise.
  • Oscar Gomez
    Oscar Gomez about 14 years
    This will work in fact that is how I did it on one of my applications. Although I did actually use the coredatabooks.sqlite example and modified it to what I needed in order to have the needed tables to work with Core Data. Sorry I should have suggested to base yourself on that table just as I did.
  • Tanner
    Tanner about 14 years
    As long as something works im happy. How did you add items to the table? What part of it did you change?
  • Oscar Gomez
    Oscar Gomez about 14 years
    First Delete all Records in the ZBook Table (leave the other 2 tables intact). Then modify the table as follow: leave the first 3 columns: Z_PK (identity key), Z_ENT and Z_OPT, delete the other columns, and add the column(s) you need. Finally add the records you want.
  • Tanner
    Tanner about 14 years
    If I do the desktop and add say 10 items. Will those items still be in it when I transfer?
  • Tanner
    Tanner about 14 years
    Also if I do it like that would there be a way to make separate list? Like 1 for the airport, 1 for shopping, 1 for school...? Thanks
  • Sjors Provoost
    Sjors Provoost over 12 years
    Won't this break your app if Apple decides to change the internals of Core Data between iOs versions (and you don't ship an update in time)?
  • Ken Aspeslagh
    Ken Aspeslagh about 12 years
    I honestly doubt Apple would make a change that breaks its ability to read its own databases files.
  • Sjors Provoost
    Sjors Provoost about 12 years
    Apple could migrate all existing core data databases on the device during a system upgrade, so it would still be able to read them. But such a migration might skip pre-packaged database files in new installs.
  • Ken Aspeslagh
    Ken Aspeslagh about 12 years
    That wouldn't work at all Sjors. App data can be backed up on the user's computer in iTunes and restored at any time.
  • user2918201
    user2918201 almost 12 years
    I did as you suggest, but I still get "The model used to open the store is incompatible with the one used to create the store". I actually copied the model file from one project to the other... so I'm pretty sure they are identical.
  • martin
    martin about 9 years
    Could anyone translate this to Swift? That would be of big help.
  • Ace Green
    Ace Green almost 9 years
    instead of creating a new app with the same model, can't we just duplicate our app or even use it, run it, create whatever data we want and just copy that sqlite store into our Xcode project?
  • Tommie C.
    Tommie C. almost 9 years
    I think you ought to revise this answer so that it states one should create a Core Data Store using normal procedures and then to distribute the store simply add the sqlite file to the project folder and the Copy Phases List. At that point one can use the process as described in the sample.
  • Oscar Gomez
    Oscar Gomez almost 9 years
    Edited answer to clear up confusion, I realize it was misleading.
  • Fattie
    Fattie over 7 years
    SQLite.swift is magic. Say @Suragch, you may know ... in Android, you have SQLiteOpenHelper which has the handy "OnUpgrade" concept. To deal with when the app is upgraded (ie, new version from the app store). Do you happen to know, how is that issue handled in iOS, does it become a problem? Cheers
  • Fattie
    Fattie over 7 years
    BTW what you say above is so true. If you are doing ios-android development, it's so much better to simply stick to SQLite. Even for those who have never used sql before, it's just a matter of learning a few simple sql statements.
  • Suragch
    Suragch over 7 years
    @JoeBlow, I haven't done a schema update in Sqlite.swift yet. I think I recall reading something about it in the documentation, but all I could see just now was this. It appears to not be as built in as OnUpgrade is with Android.
  • Fattie
    Fattie over 7 years
    thanks for the reply; right, saw that section "Migrations and Schema" - perhaps that's the size of it. Thanks. BTW I asked a question on the issue, stackoverflow.com/questions/41100001/… Cheers!!
  • bmueller
    bmueller about 7 years
    If anyone is trying to do this post-iOS 9, Core Data now saves data to a sqlite-shm and sqlite-wal file in addition to the regular sqlite file. You need to copy those files over as well, otherwise you'll get an empty database.
  • Phuah Yee Keat
    Phuah Yee Keat over 5 years
    It is allowed for "small data set" as per developer.apple.com/library/archive/technotes/tn2350/…