In this screencast I will show you how to tear down your Core Data Stack. Documentation on this topic is a little sketchy to say the least.
We’ll create a new Master/Detail app and implement a button that will remove the store file and reset the entire stack – without nasty error messages or app crashes. The app will work on iOS 7.1 and iOS 6. I’m using Xcode 5.1 in this demo. The principles of course apply just as much to Mac Development.
Notice the absence of a Configuration in the addPersistentStoreWithType method. You can create Configurations by click-holding the big PLUS button that let’s you add Entities by default. GIve them a meaningful name, then drag-and-drop in your Entities:
Next you’ll replace the code above with something like this, adding more than one store file to your Persistent Store Coordinator:
Core Data can handle several versions of your Model. It’s easy to add a version (via Editor – Add Model Version) and set it active, but it’s not so easy to remove a version you no longer need.
Thankfully there is a way to delete version files which goes a long way to declutter your brain. The secret lies in the fact that the .xcdatamodeld file is actually a Package and can contain more than one file. It’s like the .app extension which isn’t just one file. I never knew this!
To explore, select your versioned .xcdatamodeld file, right-click it and select “Show in Finder”. Once in there right-click it again and select “Show Package Contents”. Surprise – here are all your Model Versions. Before you go on a mad deleting spree, head back to Xcode and do the following:
activate a Model Version that you want to keep (by going to the top level .xcdatamodeld entry, then select it under “Versioned Core Data Model”)
next remove the entire file from your project (just the reference… do not move to trash)
head back to the Finder and delete the files inside the Package you no longer want
go back to Xcode and add the .xcdatamodeld file again
Voila – now all your unnecessary Model Versions are gone. Perhaps in a future version of Xcode there will be an easier way to do this, but as of Xcode 4.6.2 (April 2013) there is not.
You can create Fetch Requests in the Xcode model editor, including a Predicate. These are somewhat easier to setup. To create one, select your .xcdatamodeld file, then head over to Editor – Add Fetch Request. Give it a catchy name and a filter property, and much of the above code becomes obsolete.
Note that to retrieve your Fetch Request Template you need a reference to your Managed Object Model as well as your context. The easiest way to grab hold of it in an iOS app is to pass it in on a property, just like we did with self.managedoObjectContext.
If the App Delegate has something that your top view controller needs then you simply pass it the required object via a property set on the top view controller. This is easy when your top view controller is also the root view controller.
However, when you embed your top view controller in a Navigation Controller, and perhaps that one is also embedded in a Tab Bar Controller, then this array isn’t quite so easy to figure out (and I must admit that I always forget how to do this when a new challenge arises).
So here’s how this works. In this example, the thing that’s displayed is called MyViewController, which is embedded in a Navigation Controller. I’m passing it the App Delegate’s self.managedObjectContext which is defined as a property on MyViewController.
By default Mac Apps use XML as store type when saving in Core Data, even though it can use other formats – such as SQLite, which is the default on iOS. Here’s a way to quickly convert one into the other.
Note that this is designed as a one-off operation to create a new store file which can be used in another application. Once run, comment the code out and either change your store file, or take the store file and use it in another app.
Add this code to the AppDelegate.m file in the persistenStore method (just before the return statement):
I was excited to find out that it is possible to write a Mac App with Core Data completely without code! This magic is possible with something that’s not available in iOS (yet) called Cocoa Bindings.
You provide the user controls you need in Xcode, then control-drag your way to extensive functionality and happiness. Before I forget, I thought I’d better make some notes.
Here’s a step-by-step list:
Using Xcode, create a new Mac Cocoa Application with Core Data
Setup your entities and properties in your Core Data Model (.xcdatamodeld)
Create relationships between Entities if desired
Select all Entities and create custom classes from them (using Editor – create NSManagedObject Subclasses)
Drag our friend the Array Controller onto the Object’s Bar. If you have multiple Entities, you need a separate Array Controller for each one. Change the labels to tell them apart (select a different file and go back to the xib in order for those labels to be visible – it’s a bug in Xcode).
Now bind the Array Controller and Core Data Managed Object Context together:
Select your Array Controller, then go to the Bindings Inspector (second from the right)
Under Parameters, head over to the Managed Object Context and bind to the App Delegate (as that’s where Xcode has kindly prepared our Core Data stack)
In Model Key Path, type self.managedObjectContext (this should self complete)
In the Attributes Inspector, tell the controller that we’re using an Entity instead of a Class, then enter the Entity (it’s the one you’ve created in the data model)
While you’re here, tick the “Prepares Content” check box if you want the table view to be populated automatically
Add a Table View to your window and bind it to the Array Controller:
Select the Table View (inside the Scroll View) and head over to the Bindings Inspector
Under Table Content, select Bind To your Array Controller
Now select the actual Table Column you want to fill with data, and still inside the Bindings Inspector under Value, bind the column to your Array Controller
In the field for Model Key Path, type the attribute/property you’d like to see in this column (you’ve defined this in the data model)
Repeat the process for each column you want to fill with data
To add data to your table:
Add a couple of Gradient Buttons to your window
Make one the “Add” and one the “Delete” button
Hook up each button to the Array Controller via control drag, selecting add and remove respectively
Congratulations: You’ve just created an editable Table View, hooked up to Core Data without a single line of code!
Let’s create a functional SAVE menu item
If you quit the app (rather than running it again from Xcode), all your data will save. However we can implement a manual save action with ease. The menu item itself is there by default, all we need to do is hook it up to the App Delegate and bind it to the save function.
In the Object Sidebar, select Main Menu, then select File – Save (which will expand the item in the sidebar too). From the save menu option, control drag to the App Delegate and select saveAction.