Command Line Tool Core Data Tutorial - xcode

I'm playing with Xcode and Objective-C/Cocoa again. This time I want to start with the bare minimum. I would like to setup Core Data in something as simple as a Command Line Tool (if it's even possible.) I need some practice saving and retrieving data without the all the View Controllers and AppDelegate stuff. Any ideas or maybe I'm going about this all wrong?

Your task will be the same as for any other project, except that the Command Line Tool template probably doesn't contain a Core Data option. No matter, you're doing this to learn, so setting up Core Data yourself won't hurt a bit.
Just create a new command line tool project and add a new Core Data model to the project. Next, you'll add the code that gets the model, creates a persistent store coordinator, uses those to create a managed object context. Then you can add objects, fetch objects, whatever you like.

Related

Is there a right way to add an existing SQLite database to a Xamarin project?

Every example I've found creates the database for you and then has you create tables and populate them in code. My problem, though, is that I would like to create and populate the database elsewhere (SQLiteStudio) and then include it in my app.
I sense (through the general feel of ...whatever I've been looking at. We'll call it documentation) that you are supposed to copy the database to the Environment.SpecialFolder.Personal directory. So my workflow is to include the database as a resource and then copy it to the Environment.SpecialFolder.Personal directory. Is that right? Has anyone written any of this down succinctly and authoritatively (as opposed to loose collections of articles)?
I'd prefer not to have two copies of the same database but if that's what everyone else is doing then ...okay.
I have not been able to find an answer on any of the following web pages.
https://github.com/xamarin/recipes/tree/master/Recipes/ios/data/sqlite/create_a_database_with_sqlitenet
https://forums.xamarin.com/discussion/8188/creating-database-with-sqlite-only-once
https://github.com/praeclarum/sqlite-net
https://github.com/praeclarum/sqlite-net/wiki/GettingStarted
https://forums.xamarin.com/discussion/3773/system-environment-specialfolder
https://forums.xamarin.com/discussion/36285/where-do-you-store-your-sqlite-database-in-the-app
https://learn.microsoft.com/en-us/xamarin/xamarin-forms/app-fundamentals/databases
Since you tagged pcl, have you tried treating this as an embedded resource? You pretty much just make a folder, drop in the database, and set the build action as an embedded resource. You can access the file through your SQLite library by linking up to the path of where the database is.
https://learn.microsoft.com/en-us/xamarin/xamarin-forms/app-fundamentals/files?tabs=vswin

Sharing code between NSDocument and UIDocument

I have created a document-based app that uses Core Data. I created the mac version first, and now that it's working properly, I am moving on to create an iOS version of it.
I just can't get my head around how to maximize code reuse between the iOS/mac versions, with respect to the Core data bit, since they don't use the same classes.
My document class that handles saving and such is a subclass of NSPersistentDocument. My intention is that a well-designed model class should work in both environments, especially since I don't do all that much fancy stuff with regards to Core data.
Now, since NSPersistentDocument isn't available in iOS, I hit a wall. I tried to get around this by using #if TARGET_OS_MAC and TARGET_OS_IPHONE and in that manner make it a subclass of UIManagedDocument in the iOS version. That obviously would have been convenient, but I can't seem to make it work like that. And it's really looks quite messy, since there are a lot of other stuff that has to be conditionalized as well.
I also tried building the classes atop of NSDocument/UIDocument instead, implementing the Core data hooks myself, but it also looks quite messy, leaving me thinking it's not the right way to go.
The question:
To me, it seems like a good idea to reuse the same document class between the iOS/mac versions, but maybe I'm being naive.
What's the best way to do this?
Should I forget about the code sharing and create a separate document class for the iOS version that emulates all the methods present in the mac version?
Am I right that the code you're wanting to share is model-related? I suggest refactoring that code to a separate object, which both an NSDocument and UIDocument contain (as rickster suggested above).
I use a DocumentRoot Core Data entity with its own NSManagedObject subclass, but if there are no properties you want to manage using Core Data, you can just subclass NSObject.
This may sound strange, but NSDocument and UIDocument are actually controller classes. (To be specific, they're part of the model-controller.) Their jobs are to load the model, set up windows, and save the model. If you need to provide an interface for higher-level access to model objects, it could be in a document root or model helper class instead.
Similarly NSPersistentDocument's job is to configure the managed object context and the persistent store and handle loading and saving. It doesn't necessarily need to provide a complete interface for accessing the model.
(Bringing this over from my comment.)
In general, the situation where you have two classes which must inherit from different superclasses but which also want to share a lot of code is composition. Put the shared code in a separate class; your NSDocument and UIDocument subclasses can each keep an instance of that class, and message it whenever they need to invoke that shared code. (Though as #noa mentions, you might want to consider whether all of that code belongs in your document class to begin with.)
Of course, then you might end up writing a bunch of methods that read like:
- (id)doSomething {
return [sharedController doSomething]
}
That can get to be a pain... so you might want to look into Objective-C's message forwarding system.

How to add new managed object from other app?

I have used Core Data just creating projects with "Use Core Data" checked, using the code that XCode creates by default and, if necessary, adding or modifying just a few things.
Now I have a "main" app and I have created a helper app (status bar item app, LSUIElement = 1 and Login item). The helper app is Build as main app target dependency and copied into the main app "Resources" folder.
When the status bar icon is clicked the helper app shows a window to the user to collect some info to create a new managed object according to the main app Core Data Model.
But, how can I create a new managed object from the helper app for the main app?
By now I´m thinking to:
check if main app is open or not (I don´t know if it´s possible)
if it´s open, let the main app to perfom a selector with a dictionary with the info sent from helper app (I don´t know if it´s possible)
if it´s close then (in the helper app) create a persistent store coordinator, manage object model and manage object context using the model and persistent store files from main app. Create the new managed object. And I don´t know if it´s better to terminate MOC, MOM and PSC each time the user creates a new MO to avoid conflicts when main app opens or it´s not optimal and could affect performance...
It´s a good approach? Any point to start? Thanks in advance
Do you have to create a managed object? If you're just collecting simple data in the helper app it would be much simpler to pass that input to the main app via the userinfo dictionary in a Distributed Notification. Then the main app could create the managed object and you don't have to deal with merging changes between the two contexts.
Otherwise you'd have to pass the helper app a path to your MOM, create a MOC in the helper app, create the object, save the MOC while notifying the main app to merge changes by passing the IDs of the changed objects, reloading your main app's model objects, and so on. I've gotten it to work, but it's a huge headache and prone to errors. I'd avoid that route if possible.
Edit: I just realized you want to be able to write to your main app's store even if it's not running. It sounds like you need to re-think this before writing any code. If the helper app executes on its own, it's not really a helper app. Could you go into more detail about what you're actually trying to accomplish? This kind of hackery is not really a good idea and could lead to data corruption.

How to preserve compatibility when loading NSPersistentDocument(s) saved using a modified entity model?

I've created an OSX app that uses the entity model builder and its related stuff, for simplicity consider the entity with only two NSString.
The app is in production and works fine, now I need to add new attributes to the existing entity (only one entity exists), but with new attributes the old saved files are not open, silently the app does't open them and the console doesn't contain any error/warning message.
I need to load old saved files, consider all new attributes are optionals and have defaults (also in code not only in model design)
All existing attributes continue to be present I've only added the new attrs.
How can I design applications able to work when the entity model change?
From OS X 10.5 onwards, there is data migration functionality to help you, as long as you make changes to the data model in a new version.
There is a good basic explanation and example here: http://www.timisted.net/blog/archive/core-data-migration/
and the Apple documentation is here: http://developer.apple.com/library/mac/documentation/Cocoa/Conceptual/CoreDataVersioning/Introduction/Introduction.html

Core Data Migration error message "'Model does not contain configuration 'XYZ'.'"

I have a Managed Object Context to which I add two different SQLite stores. I use Configurations in the Mananged Object Model to assign certain entities to one store and other entities to the other. The Configurations are called "UserDB" and "MainDB".
Everything works okay until I try to use automatic migration. After creating a new Managed Object Model version, and adding a new attribute to one of the entities in the UserDB Configuration, I get an exception when adding the old version store (for the UserDB related store) to the store coordinator: 'Model does not contain configuration 'UserDB'.' I can find no hits for this error on Google. Anyone out there using multiple stores with Configurations? Anyone have an idea what I might be doing wrong?
The stack looks like this:
objc_exception_throw
-[NSManagedObjectModel isConfiguration:compatibleWithStoreMetadata:]
-[NSStoreMigrationPolicy sourceModelForStoreAtURL:metadata:error:]
-[NSStoreMigrationPolicy(InternalMethods) _gatherDataAndPerformMigration:]
-[NSPersistentStoreCoordinator addPersistentStoreWithType:configuration:URL:options:error:]
-[MyAppDelegate persistentStoreCoordinator]
This looks like a bug with migration+configurations. I was able to work around the problem by going through the same motions and passing nil for configuration when calling addPersistentStoreWithType. The migration happens, and then I can make a new persistent store coordinator and add the stores again with the proper Configuration string arguments.
This is the second configuration related bug I've run into. Not a well tested feature apparently.
I had the same problem. The fact pattern was identical and the error message the same. It turned out, however, to be the result of my own mistake.
Let's say the old model was Blah.xcdatamodel and the new Blah 2.xcdatamodel. I had started making changes to Blah before realising my mistake and creating Blah 2. I then used my version control system (Git) to revert to the old Blah and then recreated Blah 2. Everything looked right. But I must have done something wrong in the reversion process, because when I thought to double check that Blah.xcdatamodel in my current project folder was really the same as Blah.xcdatamodel in the project folder I used to build the previous version of the app (fortunately I always keep a zipped archive of the project folder for each released version as I don't fully trust version control systems), I found that they were in fact different, albeit that they looked identical in XCode. The file size was different, for instance.
I substituted the old Blah into my current project folder, and lo and behold it all went perfectly, without any need for the workaround described by Ken.
I am not saying that Ken had necessarily made a similar mistake, but if you do encounter this message it is at least worth confirming that the model you are migrating from is REALLY the model that was used to create the data in question.

Resources