Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Core Data Store included in App Bundle

I can't find a clear description of these steps in Apple docs...

  1. I have a xcdatamodeld in my xcode project
  2. At launch time, my app parses a XML (project resource) to fill the Core Data Store (SQLLite)
  3. During lifetime of my app, I add, remove, update data of that Store

Now, I want to stop doing that heavy XML parsing process on device and directly include a Store containing the required data.

I have some questions regarding this :

  • Can I fill a store with a OS X app and then include this store in my XCode-iOs project ?
  • My store does not appear in Xcode. In fact it is created at run time. How can I add a store in the project and link it to my xcdatamodeld ?
  • I have read that doing so will prevent my store from being writable... I guess I have to copy it in the right place at launch time (the Core Data utility Tutorial is a great help for that). Am I right ?

Thanks for your hints. URL or other SO questions would be really appreciate !

Kheraud

like image 298
kheraud Avatar asked Apr 12 '11 09:04

kheraud


3 Answers

You can include the store file (sqlite db most of the time) in your app. Then in your app delegate edit the persistentStoreCoordinator getter merhod :

- (NSPersistentStoreCoordinator *)persistentStoreCoordinator {

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

    NSString *storePath = [[self applicationDocumentsDirectory] stringByAppendingPathComponent: @"CoreDataStore.sqlite"];

    // Check if the store exists in. 
    if (![[NSFileManager defaultManager] fileExistsAtPath:storePath]) {
        // copy the payload to the store location.
        NSString *bundleStore = [[NSBundle mainBundle] pathForResource:@"YourPayload" ofType:@"sqlite"];

        NSError *error = nil;
        [[NSFileManager defaultManager] copyItemAtPath:bundleStore toPath:storePath error:&error];

        if (error){
            NSLog(@"Error copying payload: %@", error);
        }
    }

    NSError *error = nil;
    NSURL *storeURL = [NSURL fileURLWithPath:storePath];
    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_;
}
like image 87
rckoenes Avatar answered Nov 17 '22 11:11

rckoenes


  1. Write a utility app using the data model and classes for the app. Use the utility app to generate a persistent store from the data provided by the XML.
  2. Add the store file to the app bundle like any other resource
  3. Pick a location in the app directory where you want the active store to reside e.g. the Library directory.
  4. Upon launch have the app check if the store is present in directory. If it isn't, the app should copy the store from the app bundle to the directory using standard NSFileManger methods just like any other file. (Usually, you only need to do this the first time the store is created. )

That's all there really is to it.

like image 26
TechZen Avatar answered Nov 17 '22 10:11

TechZen


What you're currently doing (populating at first launch) is the "recommended" way of populating a Core Data store. Although its a bit hackish, you could however seed the on-device database as follows:

  1. Launch your app in the simulator
  2. Do whatever you need to do for the simulator app to populate the Core Data store
  3. Stop the simulator app
  4. Navigate to the simulated Documents folder (something like ~/Library/Application Support/iPhone Simulator/4.3/Applications/335567A0-760D-48AF-BC05-7F0D9BD085B6/<app-name>.app/)
  5. Find the sqlite database (it has the name you gave it when initializing Core Data)
  6. Copy this database to your project, and add it to be copied as a resource
  7. Add some code to your application:didFinishLaunchingWithOptions: method so that on first launch, it copies the database from the read-only resources directory to the app's documents directory. Of course you need to do this before initializing Core Data.

Depending on exactly what you're storing in your database, you may however discover big- vs. little-endianness issues, or other incompatibilities. To make the approach a bit safer, you could dump the simulator database (splite3 databasefile .dump >dumpfile) on your Mac, then include the dumpfile in your project (as above), and slurp the dump in your app on first launch (reading it line-by-line, and handing the sql statements to the sqlite API).

like image 8
odrm Avatar answered Nov 17 '22 11:11

odrm