Strange things creating a new document-based Cocoa application on Xcode - xcode

I am new to cocoa development.
I just created for the first time a new document type application using core data and notice a few strange things.
AppDelegate is practically empty, there is no code to create the core data store, the managedObjectContext, nothing.
Two files were added: Document.m and Document.h that I understand is the model for dealing with the documents the app will create.
Even with no visible core data initialization code, Xcode created a .xddatamodeld file and this is the strange part: Xcode named the file Document.xcdatamodeld. Normally Xcode would name that with the same name of the project. By naming it Document it is like saying that this model has something to do with Document.m and Document.h.
Is 1 and 3 a bunch of nonsense from Xcode or am I missing something?
Can you guys explain? Thanks.

Short answer to your questions: the behavior you're seeing is caused by you creating a document-based application. If you created a shoebox (non-document-based) application, you would see different behavior.
Regarding Question 1, when you create a new document, NSPersistentDocument creates a Core Data store and a managed object context for the document. Each document has its own Core Data store and managed object context. Creating the store and managed object context in AppDelegate is fine for a shoebox application because a shoebox application has one set of data for the whole application. But creating a store and managed object context in AppDelegate makes no sense for a document-based application because there can be multiple documents open, each with its own store and managed object context.
Regarding Question 3, the data model has the name of the document because a document-based application creates documents. Suppose you're creating a screenwriting application with a document name of Screenplay. When you choose File > New in the application, you're creating a new screenplay, not a new instance of your application. That's why the data model has the name of the document, not the name of the application.

Related

Correct directory for NSPersistentDocument OSX

I am writing a shoebox type application wherein a user enters data into a single window. I’ve configured the data model with Code Data. Apple’s documentation states that user data should be stored in a Library Directory, however the auto-generated code seems to make a directory in the Application Support directory where one, the documentation also states, “should never store user data.” Which is correct?
The other question I have is should I not create an instance of NSPersistentDocument in the applicationDidFinishLaunching method?
User-created data should be managed by the user: the user should decide where they are saved, etc.
Application-created data would indeed belong in the application support directory. If your application creates an NSPersistentDocument without user intervention, this would be the correct place to store it. For example, if you were using NSPersistentDocument to manage application data it would belong in a sandboxed directory such as NSApplicationSupportDirectory.
The File System Programming Guide goes into this in more detail.

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.

Core Data supplied doc at startup

Thanks for the help.
Core Data doc based app/sqlite format.
A few things I know I can do:
Running the app for the first time displays an "untitled" document. I can add data, save, and subsequently run the previously saved document at startup with additional code. No problem with this. It's all working.
What I need to do is supply a previously created sqlite file that contains data and have the application immediately run it at startup, bypassing the display of an "untitled" document.
I'm set with sending the sqlite file located in my application bundle to ~/Library/Application Support/Some App/dbase.sqlite. How do I set things up so that upon launch - this default document runs at startup?
I'm doing it this way to make things easy for the user: choosing the supplied database - or the option to create custom docs stored in different locations, if necessary.
Thanks again.
Paul.
In your NSApplication delegate, you should implement the ‑applicationShouldOpenUntitledFile: delegate method and return NO. This will prevent the app from creating a new, untitled document at launch.
You should then implement the ‑applicationDidFinishLaunching: delegate method which is called once the app has finished loading. In your implementation you should call the ‑makeDocumentWithContentsOfURL:ofType:error: method of NSDocumentController to open the file you wish to display.
You can get an instance of the document controller with:
[NSDocumentController sharedDocumentController]
You can get the URL for your document using:
[[NSBundle mainBundle] pathForResource:#"YourDocName" ofType:#"YourDocFileExtension"];

NSArrayController and referring to a shared, static, Core Data based library

Using this guide I have created a static library (let's call it AppCore) that can be shared between the Mac OS X and iOS versions of one app. This static library uses Core Data and the point of it is to share the model part and schema versioning between different implementations.
I created a NSPersistentDocument based project that will depend on this AppCore. In this project I added a reference to the .xcdatamodel file. Then I created a simple table view with add/remove buttons to edit an array of one entity type with the assisted "new core data entity" item. This created an instance of NSArrayController and the required bindings for the add/remove behaviour.
Now, everything seems to work fine when I'm using the default class for the Core Data entities (NSManagedObject) and I'm able to add new rows using the +/- buttons. However, when I change the entity implementation class to a custom one, I'm getting an error
Failed to create new object
This seems to come from the NSArrayController and it seems to be unable to instantiate the required entity. I can, however, create one in the NSPersistentDocument subclass by:
[NSEntityDescription insertNewObjectForEntityForName:#"SomeEntity" inManagedObjectContext:[self managedObjectContext]]
What confuses me is why the instance of NSArrayController can't. If I understand correctly, the array controller is instructed to create an entity, not class and my guess is that the entities are created with the help of NSEntityDescription class. I could implement my own version of the array controller's add: but then again, it might be that here something is fundamentally wrong. I haven't touched the init:s and the custom entity class implementation is simply for convenience, to access the attributes directly.
I have tried changing the base SDK on the AppCore but without effect. Currently it uses the iOS version but I'm not sure how it should be. This is another question but if unrelated, I might ask it here on a separate question.
So, to summarize, why can't the NSArrayController create an instance of this entity?
Thanks in advance.
Update
This works if I add the SomeEntity class from the AppCore to the dependent project as a reference. This is not the most usable way since modifications to the AppCore has to be propagated to the dependatnt projects also.
Bingo. I missed the "-ObjC" flag for the dependant project's "other linker flags". Now everything works like a charm.

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

Resources