UPDATE 2 Aug 2011: Some of you have requested a revised version of this tutorial that covers Xcode 4, I have completed that post and it is now located here. You should also note that I will not be adding any tutorials to this site anymore as I have moved my blog to my main development website theMikeSwan.com.
This is the first in a series of tutorials that combines other tutorials I have seen and in the end will go a little past the others I have seen. My intention is to take this app from beginning to end, including the finishing touches like update checking, serial number, and icons. I am writing this to help me figure out a few things about Core Data and hopefully help others as well.
This tutorial assumes you have the Apple Developer Tools installed and are familiar with basic operation of Xcode and Interface Builder. It also assumes that you have a very basic knowledge of Core Data. If you are completely new to Core Data check out either Build a Core Data App or read chapters 11 & 30 of Aaron Hillegass’s book Cocoa Programming for Mac OS X 3rd Edition. Really if you are new to Cocoa you should have a copy of Aaron’s book no matter what, it is the one book I always go to when I’m not sure about something. We will also be doing a little with bindings, if you need a starter check out either Cocoa Bindings Intro or Chapter 11 of Aaron’s book.
This is the first tutorial in the series so we should first specify our goal. First off the purpose of the app will be to track daily expenses. Every feature we think about adding should be assessed based on that one sentence, this will hopefully help keep down the feature creep. Since the purpose of the app is to track expenses we will just call it Expenses. Now we should determine the major features of the app. It will of course need to store expenses, perhaps when, what, & how much. To make life easier it would be a good idea to be able to assign each expense a category so the user can figure out things like how much they spend on food versus movies. It would also be good to show how much was spent in a month on any one category, as well as overall (this is a feature I will need some help with). Of course we will also show yearly totals both by category and overall. We are also going to want to let the user know when we release new version of the app without having to e-mail them (they don’t want the e-mail and will ignore it). Since we are putting all this effort into writing this Expenses perhaps we want to get paid for it, in which case we will want some way to require a serial number for real use of the app. Finally in order to improve the user experience we should get crash reports so we can figure out how to reduce (if not eliminate) them. Of course along the way we will come up with a few smaller features (such as copy and paste of expenses) that we will add in, but this should be the bulk of it. We will use Core Data to build Expenses because it is extremely well suited to this kind of work and will reduce the amount of code we have to write dramatically.
Today we are going to start by just building the basic app without writing any code at all!
To start with open Xcode and start a new Document based Core Data application.
Name it Expenses (or whatever you want to call it).
Next set up the model as below.
Attributes:
Expense |
Category |
||
Name |
Type |
Name |
Type |
desc |
string |
name |
string |
date |
date |
|
|
amount |
float |
|
|
Relationships:
Expense |
Category |
||
Name |
Destination |
Name |
Destination |
category |
Category |
expenses |
Expense (to-Many) |
In the end the model should look like this:
Make sure you save.
Next let’s build the user interface.
Open MyDocument.xib
Remove the Label.
Add a tab view.
Size it to take up most of the window.
In the inspector select the size tab and set the springs and struts so that the tab view resizes with the window.
Label one of the tabs “Expenses” and the other “Categories.”
Make sure the Expenses tab is active, then drag over a Core Data Entity from the IB Library. It will bring up the “New Core Data Entity Interface” assistant:
Select Expenses -> MyDocument -> Expense as below, then click next.
In the next pane select “Detail/Master View” and select “Detail Field” & “Add/Remove.” If you want you can also select “Search Field” to get basic searching for free.
In the last pane select all of the attributes and the one relationship:
You should have something that looks similar to the image below. It needs a little work, first off lets get rid of that extra box (Layout -> Unembed Objects).
Next lets make a few other tweaks. Date should really be the first column; Description, the second; followed by Amount, and Category. Amount will need it’s number formatter adjusted to display currency in whatever way you want. You will likely want to adjust the date formatter in the date column (unless you want the really long default format). Then resize the the table and it’s columns to something resembling the image below. Once that is done collect all the detail fields and put them in a box at the bottom. you will also need to adjust the formatters for the date and amount fields to match the ones in the table view (unless you want them to be different of course). In the end it should look something like this:
Before we do the other tab we should make life easier if we have to change any bindings later. You should have two array controllers in you xib file now, one named “Expense Array Controller” and one named “Category Array Controller.” When you drop the Category entity into the other tab IB will add in another “Category Array Controller” making it very hard to tell which is which. To eliminate this problem rename “Expense Array Controller” to “ExpenseView Array Controller” and “Category Array Controller” to “CategoryPopUp Array Controller” this just makes everything way more clear for the future.
Now select the Categories tab and drop a Core Data Entity on it. follow the same procedure as before (only select the Category entity of course). Re-arrange the interface to look like below. Go ahead and rename the new “Category Array Controller” to “CategoryView Array Controller.”
If you are wondering what that huge empty space is for, it’s for the table view that you need to add now. It should have three columns; Date, Description, and Amount. Below the table view add two labels; “Total:” and a placeholder with a number formatter set to your favorite currency settings (I tend to use “$10,000,000.00” as my place holder since it should always be big enough for any numbers I will ever be entering).
Now to fill that nice new table view with some data. First add a new array controller and name it “ExpenseByCat Array Controller.” Now your xib file should look something like this:
See how easy it is to figure out which array controller does what.
In the bindings section of the inspector for “ExpenseByCat Array Controller” bind the Content Set (not the Array) to “CategoryView Array Controller.selection.expenses” this will cause the array controller to be filled by the expenses of the currently selected category.
Now that the array controller is hooked up we need to bind the table view columns. Bind each column to “ExpenseByCat Array Controller.arrangedObjects” and set the “Model Key Path:” as needed for each column.
Then select that placeholder label that you put below the table view earlier and bind it the same as the table view columns (“ExpenseByCat Array Controller.arrangedObjects”) for the “Model Key Path:” though you are going to enter a little magic: “@sum.amount” this will take care of adding up all the amounts of each expense in the category for you.
Build and Go!
You should be able to add and remove Categories and Expenses. Undo should already work. Saving and reverting should work. So should the total for each category, that’s a lot of stuff with out writing any code yet! But there are some things that would be nice to add.
In the next installment we will add:
- New expenses default to the current date.
- Alphabetize categories in the popup menu.
- Make expenses start out sorted by date and keep them that way even when the date is edited.
- Copy and paste of expenses.
Let me know what you think or if I missed something (after all I am still fairly new at this). Also if you have any ideas about how to sort out how much was spent in each category for each month please let me know.
May 22, 2009 at 2:07 pm |
[…] And there's a new tutorial series starting here that looks worth following as […]
June 1, 2009 at 4:59 am |
Just nothing to add 🙂 It’s a wonderful tutorial! Thank you Mike!
August 30, 2009 at 9:08 am |
The tutorial is very helpful. In terms of appearance, I’d just change the screenshots to use the full window capture in the screen grab utility. (cmd-shift-4, followed by a tap on the spacebar) You’ll get only the window, with drop shadows, etc.
Keep it up though!
October 7, 2009 at 2:16 pm |
[…] theMikeSwan: Coredata tutorial […]
December 9, 2009 at 5:00 am |
This is a great tutorial. I mainly develop in the Windows environment and am new to Objective C and Cocoa. Once you get your head wrapped around the idea of IBOutlet’s and IBAction’s, the rest is pretty easy.
With that said, there is one area that I’m not really used to, or perhaps just don’t understand. For example, one can write out bits and pieces of code in the watch window in Visual Studio, like: isSomething == toThisVariable and it will print out in the watch window the result or do what ever other calculation.
Other than that, Xcode is pretty cool.
December 16, 2009 at 10:18 pm |
I’m not sure I fully understand your comment, but I think you may be looking for NSLog(). You could for example do something along the lines of: if (isSomething == toThisVariable) NSLog(@”isSomething == toThisVariable”); else if (isSomething != toThisVariable) NSLog(@”isSomething != toThisVariable”); There is likely an easier way to do this that I have not thought of yet but you get the idea I hope. I use NSLog() a great deal when first working on a new bit of code to see how things are going.
April 27, 2010 at 6:22 am |
Do you have a similar tutorial to build in iPhone environment ?
May 2, 2010 at 10:32 am |
I just want to thank you for taking the time to create this example and share it. I am a seasoned programmer, but I’m new to Mac development. I find the binding options in IB very complex, and your example help me to stop over complicating the situation. For example: I had bindings for both the TableView and the columns in my application, which caused some very odd behavior in the code. Anyway, thank you again!
May 2, 2010 at 5:09 pm |
Hi Many thanks for this tutorial – have used your example on another program (my own personal training) which is working fab
if I was to add a button next to the amount field and if clicked would put ‘500’in the amount field – how would I do that ?
best Regards
May 3, 2010 at 8:03 pm |
I haven’t ever tried anything like this, but I would start by making an IBOutlet for the amount field and an IBAction too set the field to 500. [amountField setFloatValue: 500.0]; or if you were looking to increase the amount by 500 [amountField setFloatValue: ([amountField floatValue] + 500)]; Both of these methods should cause the model to get updated.
May 28, 2010 at 10:50 am |
Great tutorial! I’ve looked at others included the ones you mentioned but the one you’ve done just clicked.
October 27, 2010 at 11:50 pm |
Great tutorial, thank you! Just a quick question, is there a way to pre-populate the array controller with some Category objects?
For instance lets say I wanted to have some default categories such as Housing, Bills, Savings, etc that were available as defaults upon startup. Is that possible?
October 28, 2010 at 1:17 am |
Check out part 3.
March 18, 2011 at 10:48 am |
Thanks a lot!
June 10, 2011 at 12:00 pm |
Have you tried this in Xcode 4? I did and found myself stumbling in the dark when I got to the point where the tutorial says “drag over a Core Data Entity from the IB Library”
Where’s the IB Library? Is it an XCode 3 thing or am I just too new to this ?
June 10, 2011 at 7:01 pm |
The library is in the lower right corner of the window. You may have to open it and/or select the library instead of one of the other options, like the code snippet library.
However, at the moment they have removed the ability to quickly generate a prototype UI (I just spoke to an Apple engineer from the Xcode team and he was unaware of any new location for the option but wasn’t sure). You can of course manually add all the interface items and bind them on your own. This method does suck a bit and I have filed a bug for it Radar # 9591386.
When I get a chance I will update the tutorial for all the added steps.
June 15, 2011 at 3:59 pm |
I too tried this and fell over at the same part as Christer. It would be great if you could do an XCode 4 re-run. Other than that, it looks like a fantastic beginner’s tutorial!
July 24, 2011 at 6:24 pm |
+1 for the Xcode 4 version please!
October 13, 2012 at 5:19 pm |
Wonderful. Thanks a bunch for sharing your knowledge.
June 5, 2013 at 9:10 am |
Reblogged this on myBlogs.