How to: standard data in core data on "install"? - objective-c

I'm working on an application which allows the user to create his own templates with controls. My question here is how I can populate some standard data in my core data database so the user can create his own templates beginning from a standard.
I heard this can be done using local json (there will be a backend using Json to communicate with the frontend), but couldn't find a good tutorial how to do this...
Is there anyone who could help me with this, or is there anyone who has some better ideas to populate this standard data?
I'm using sql script now to populate my data now, but it's not a solution from the moment you install it on an iPad.
Update
I'm willing to create standard entries in my database, so there are some standard controls on the standard template (with template, I mean the controls on a form defined by the user). To be something more specific, how can I parse local json to my core data database?

Yes, JSON is an option.
Simply transfer the JSON into a Foundation object, like this
NSData *jsonData = [jsonString dataUsingEncoding:NSUTF8StringEncoding];
NSArray *dataArray =
[NSJSONSerialization JSONObjectWithData:jsonData options:0 error:nil];
Now iterate through your new JSON object (an array in this case, but could be a dictionary) and populate your Core Data store one by one with
[NSEntityDescription insertNewObjectForEntityForName:#"Entity"
inManagedObjectContext:self.managedObjectContext];
and save.

Related

Steps to take in migrating data from Core Data to Realm?

I was reading this article by Tim Oliver (Migrating an App from Core Data to Realm) and I came across the following paragraph, which has been the most guidance I have been able to find as far as converting my app from Core Data to Realm:
"Once you’ve migrated to Realm, you can re-link the Core Data framework back into your app, use raw NSManagedObject objects to fetch your users’ data from Core Data, and then manually pass it over to Realm. You can leave this migration code in your app permanently, or simply remove it after a sufficient period of time has passed."
This seems like a good idea; however, I have not been able to find even one example of how this should be done.
I have already changed all of my Core Data classes over to Realm, so they cannot be used any more. I have the xcdatamodel file available to the app and the core data framework is easily turned back on. Do I need to set up the whole persistent store controller, managedObjectContext, etc. all over again?
While undesirable, that can be done if necessary. Then I am left to figure out, given that 'raw' NSManagedObject will need to be used, how the many-to-many and one-to-many relationships and their inverses will be able to be properly captured.
Can anyone point me in the right direction on this? I am using objective-c but would benefit from examples in Swift if there are any to be pointed to.
I'm the Tim Oliver who wrote that article. :)
So in my own app (for which that article was based on), when I moved from Core Data to Realm, I did a clean break. All of the data I was storing was just cached metadata derived by the document files in the app, so I opted to simply delete the Core Data SQLite file on disk, and then it was only going to be a mild inconvenience the next time the user opened the app as the metadata was re-calculated and stored in Realm.
If you've got data in your Core Data file, then the onerous is on you to perform a one-off migration from Core Data to Realm. It's not recommended to access the raw data from the SQLite file directly, so the only way is to keep your Core Data code around and use it to query and copy the data.
What I meant by 'raw NSManagedObjects' is that since Core Data objects are KVC-compliant, if you've already refactored your model classes into Realm classes, you can access the data straight from the base NSManagedObject class using the KVC methods like -[NSObject valueForKey:].
I briefly tested this in one of the official Apple Core Data sample code projects to confirm it was still working.
Originally, accessing data from a Core Data Book object looked like this:
- (void)configureCell:(UITableViewCell *)cell atIndexPath:(NSIndexPath *)indexPath {
// Configure the cell to show the book's title
Book *book = [self.fetchedResultsController objectAtIndexPath:indexPath];
cell.textLabel.text = book.title;
}
But once you've refactored your Book class into RLMObject, you can still access data from your Core Data store like this:
- (void)configureCell:(UITableViewCell *)cell atIndexPath:(NSIndexPath *)indexPath {
// Configure the cell to show the book's title
NSManagedObject *book = [self.fetchedResultsController objectAtIndexPath:indexPath];
cell.textLabel.text = [book valueForKey:#"title"];
}
In this way, you should still be able to access the data in your Core Data objects like before, but you're free to use the actual classes for Realm now.
Unfortunately, like you mentioned in the comments, this does mean you need to keep some amount of Core Data code around in order to be able to open the Core Data store and get the data out of it.
But ideally, you should be able to confine all of this code to a single 'migrator' class that only needs to run the first time it detects that the user's data hasn't been copied to Realm yet. And after a sufficient amount of time has passed, you could then consider dropping it completely.

Core Data app does not generate spotlight indexable metadata (or i can not find it)

I have a sandboxed, Mavericks only, Core Data, non-document, Mac application.
For one attribute of one entity I selected „Index in Spotlight“,
and in a second attempt I selected „Index in Spotlight“ and „Store in External Record File“.
Following Apples Core Data Spotlight Integration Programming Guide i am at the first point, Your program:
There are three processes involved in creating and maintaining the
Spotlight index:
Your program. Within your program, the Core Data framework maintains
the persistent store and creates the external record files to trigger
the spotlight indexing
The Spotlight importer. [...]
Core Data External Record daemon. [...]
I assume, now, there must be some place where metadata (that a Spotlight Importer could index) or external record files will be generated if I run the application and add data in it.
I can nowhere find such metadata or external record files. I searched everywhere in- and outside the sandbox container of my application. (Note, i am not trying to build the Spotlight Importer yet — i am merely looking for the metadata to be indexable.)
Where would this spotlight indexable metadata normally be found?
What could be the reasons no spotlight indexable metadata is generated?
The directory for the external records has to be in ~/Library/CoreData (or the equivalent in a sandboxed application). You must create it.
Also don't forget to set the store options for your PersistentStoreCoordinator, in the Application Delegate, like this in - (NSPersistentStoreCoordinator *) persistentStoreCoordinator :
//creating the External Records Directory
error = nil;
NSString *externalRecordsSupportFolder = [#"~/Library/CoreData/YOUR_EXTERNAL_RECORD_DIRECTORY" stringByExpandingTildeInPath];
[fileManager createDirectoryAtPath:externalRecordsSupportFolder
withIntermediateDirectories:YES
attributes:nil
error:&error];
if(error){
[NSApp presentError:error];
}
//options for your main Persistent Store Coordinator
NSDictionary *storeOptions = #{
NSExternalRecordExtensionOption:#"YOUR_EXTERNAL_RECORD_EXTENSION",
NSExternalRecordsDirectoryOption:externalRecordsSupportFolder,
NSExternalRecordsFileFormatOption:NSXMLExternalRecordType
};
Then you pass the storeOptions
NSPersistentStoreCoordinator *coordinator = [[NSPersistentStoreCoordinator alloc] initWithManagedObjectModel:mom];
if (![coordinator addPersistentStoreWithType:NSXMLStoreType configuration:nil URL:url options:storeOptions error:&error]) {
[[NSApplication sharedApplication] presentError:error];
return nil;
}
External record data is stored in the same directory as your primary Core Data files (i.e. your SQLite file), but in a hidden subdirectory. The naming convention for the subdirectory is .ApplicationName_SUPPORT/_EXTERNAL_DATA .
For non-document-based applications, Core Data creates a directory structure within ~/Library/Caches/Metadata for the application. The directory structure may vary with the OS version, Core Data version, etc. At some level there should be an application-specific directory within that structure, and inside that should be the external records file(s) created by Core Data.
If you cannot find these files, use kqueue events, lsof, or libdispatch to monitor the filesystem for changes while you run your application. You should be able to see what locations on the file system are being accessed easily. If external records files are not being created, or are being created in some new location, that too should be obvious.
Spotlight metadata is not stored in discrete files but in Spotlight's own data. You can inspect the metadata of a file by using the mdls command from a terminal.
Example:
mdls /Applications/Maps.app
You can also use the mdimport command to tell Spotlight to index something on demand.
Example:
mdimport ~/Documents/MyAwesomeStuff
mdimport also has a command line option to use a specific importer rather than a system importer. This can be very useful for development. Both mdls and mdimport will print out help messages detailing these arguments if asked.
In the core data model editor, you can check the spotlight indexing for each individual attribute.
Select the attribute and open the Data Model inspector
Check "Index in Spotlight"

core data versioning on document based applications

My application uses Core-data. Now, with the release of the new version I need to change the database structure.
I know this is done via versioning, but all I have found, all tutorials are not for document based applications and at some point i get stuck. How can Versioning be implemented on a document based application, where the document is the database itself and can have any name?
Thanks
---Additional info----
what i would need to do is: open the application, hit the "open" button, select the NSManagedDocument from the filesystem. that is my database (can have any name) if on opening it detects that it is an old structure it should update its structure to the current one. (one column added)
It seems to me that the fact that you are wrapping the SQLite store into an NSManagedDocument is irrelevant to the model versioning procedure.
Just proceed by adding the persistent store options in code and the new model version in Xcode.
When setting up your core data stack - i.e. after the document with the DB has been chosen - you have to add these options to the persistent store when creating the persistent store coordinator:
NSString * const NSMigratePersistentStoresAutomaticallyOption;
NSString * const NSInferMappingModelAutomaticallyOption;
As the names of these options imply, it should work automatically from here. The actual call would look something like this:
[persistentStoreCoordinator
addPersistentStoreWithType:NSSQLiteStoreType
configuration:#"Default"
URL:fileURL
options:#{NSMigratePersistentStoresAutomaticallyOption : #(YES),
NSInferMappingModelAutomaticallyOption : #(YES)}
error:&error];

Returning two strings from php to ios

I'm creating an app that gets some values from a mysql database via php.
I've gone as far as returning a string that's echoed via php and using it in objective C.
Here's what I have so far:
NSString * strURL = [NSString stringWithFormat:#"http://localhost/search.php?name=%#",name];
NSData * dataURL = [NSData dataWithContentsOfURL:[NSURL URLWithString:strURL]];
NSString * result = [[NSString alloc] initWithData:dataURL encoding:NSUTF8StringEncoding];
NSLog(#"%#", result);
Is it possible to return 2 different strings from php and using them separately in xcode or do I have to make 2 different calls to the php file?
Thank you very much for your help!
Great start!
Consider using some structured way to return data from PHP. One easy format that you can learn, which will help with other API integration later, would be JSON.
Apple ships some simple code to to the conversion in iOS5 with NSJSONSerialization
On the PHP side, play around with json_encode. You can pass in an indexed array, for example, which will give you an NSArray on the iOS side.
Some more examples for the iOS side:
How to use NSJSONSerialization

Updating live app in store to use Core Data that currently does not use Core Data

I currently have an app in the store which is SQLite-backed and does not use Core Data. In the past when I have wanted to release an update that had SQLite changes, the update would include some code that would detect the version of the app, and programmatically update the tables if necessary. Now I am working on an update that uses Core Data. I don't care about any of the old data that is currently live, and I know how I can delete all the old SQLite tables programmatically. Are all the Core Data model files included in the update binary, or do I have to programmatically generate some or all of the Core Data model? Will the .xcdatamodeld be included with the binary? Any other pitfalls I should be wary of?
Thanks for your help
With core data it can be quite tricky when updating to a new version. I have experienced many times that even the slightest changes in the core data model cause weird app behaviour (understandable to some extend). The easiest way to avoid any unwanted sideeffects is to just change the name. Here the code
- (NSPersistentStoreCoordinator *) persistentStoreCoordinator {
// D_IN;
if (persistentStoreCoordinator != nil) {
return persistentStoreCoordinator;
}
persistentStoreCoordinator = [[NSPersistentStoreCoordinator alloc] initWithManagedObjectModel: [self managedObjectModel]];
// Allow inferred migration from the original version of the application.
NSDictionary *options = [NSDictionary dictionaryWithObjectsAndKeys:
[NSNumber numberWithBool:YES], NSMigratePersistentStoresAutomaticallyOption,
[NSNumber numberWithBool:YES], NSInferMappingModelAutomaticallyOption, nil];
NSURL *storeUrl = [NSURL fileURLWithPath: [[self applicationDocumentsDirectory] stringByAppendingPathComponent: #"myData073.sqlite"]];
NSError *error = nil;
if (![persistentStoreCoordinator addPersistentStoreWithType:NSSQLiteStoreType configuration:nil URL:storeUrl
options:options error:&error]){
NSLog(#"Unresolved error %#, %#", error, [error userInfo]);
}
// D_OUT;
return persistentStoreCoordinator;
}
So all you really have to do is to change the name myData073.sqlite to for example myData074.sqlite
The data model description file is not really part of the binary, but the model behind it with all the classes and access methods surely is. You do not need to worry about that. ps even during development I change the name frequently, otherwise one might waste lots of time looking for coding errors that are not really there...
An App Store update replaces the entire app bundle, so everything in your app bundle, including any Core Data model, will be included. You can test this by installing an Ad Hoc or developer build over an App Store build on your own device (without deleting first). In the compiled App, the model files are compiled or processed, and have different extensions (.momd, .mom). So you'll see those instead of .xcdatamodeld or .xcdatamodel.
Other pitfalls: Now, the Core Data data file is not part of your bundle. If you want the updated app to start with an empty database, you don't have to do anything special. But if you want to install/update with a prepopulated database, you have to figure out a way to get that database into a read-write location on the device. Basically, you generate a Core Data file, included it in the app bundle as part of your Xcode project, then at first launch, programmatically copy it somewhere in your Documents or Library folders (using the correct Cocoa API for finding these).
Pitfall #2: modifying an empty core data file with SQLLite on the Mac is suggested on some web sites, but specifically dis-recommended by Apple. Instead, you might write an iOS app that puts data into core data and run it in the simulator. How do I initialize a store with default data?
As user387184 indicated, your next update that changes the model on an existing Core Data database can get tricky. Try to get the model as right as you can the first time.