This is cocoa-specific, though some of it generalizes.
I'm not a huge fan of the Hillegrass book for actual beginners, but sadly there's not a better book out, yet; it's almost easiest to learn some other, better-documented GUI application framework, then come back to Cocoa (assuming you have time).
Assuming you don't have that kind of time, though, here's my recommendations:
Cocoa development also depends heavily on the workings of NSApplication, and it's a good idea to stop and read up on how that works; it's super helpful to actually know what's going on between the points where the code you wrote is being used, and to understand that you need to have a working understanding of how NSApplication is structured.
Apple has ok docs on this (I'd start by reading up on NSRunLoop, then looking up anything you encounter you don't understand), but nothing amazing.
Once you've gotten that understanding, you'll have a much easier time understanding what you have to do to make an application do what you want.
Now we move on to handling specific applications.
I suggest the following design algorithm:
"Simultaneously", start figuring out your application's user interface and its data model. I say "simultaneously" but it's really a bit of a back-and-forth.
For example, you decide you're going to write a blogging client (I think this is an example in Hillegrass's book?).
So, ask yourself what data items does a blog post typically have? Provisional answer: title and body.
What user interface elements do you need for a blog post? The data model dictates those: right now, a text field for title and a larger text field for the body.
If we were going to be more realistic we'd probably want a richer data model (some "authored by" field, some field for "tags" or "categories", etc.) and a more-complicated user interface to match.
If you hit a "stopping point" in this process -- meaning, a point @ which you are satisfied that your data model covers everything it needs to and your user interface elements are complete -- we can move on to the next step.
The next step is getting a sheet of paper, or a whiteboard, etc., and putting up some representation of each user interface (eg: each type of window or dialog), with lots of space between them.
Next, you go through each user interface item and ask
- "what information does this item need to display itself properly"? (eg: a blog-post-editing view needs the blog post's data object.) You should annotate each user interface item with some representation of the data item(s) it needs to render itself.
Once you've done that, you make another pass through each user interface element, asking the question:
- from this user interface item (say, the blog post editing window), which other user interface items can I get to? Which other user interface items can I be arriving from?
Once you've done that, you go back through and ask the following question for each "entry path" into a user interface item:
- for each entry path into this user interface item, what information would I need to set up this user interface item correctly? (for example: if you're editing an existing post, you need to have the data object corresponding to the post you're editing; if you're creating a new post, maybe you need nothing, or maybe you need some kind of placeholder reference to the post-to-be-created)
Note this is DIFFERENT from the step where you listed the data item(s) the user interface item needed to render itself. For example, to render itself, the blog-post-editing-view needs SOME blog post data object; however, if you're moving from a list of all blog posts to editing a specific blog post, the blog post editing view needs THAT SPECIFIC BLOG POST.
Once you've done that, you make a final pass, asking the following question for each "exit" path:
- for each exit path from a user interface item, can I supply the information the user interface item I'm entering needs? (ie: if you're leaving the "blog posts" listing view to go edit a blog post, the blog-post-editing-view needs the blog post's data object; can you supply it?)
For example: if I'm leaving the "blog post listing view" and heading into the "blog post editing view" to edit a specific blog post, then the "blog post editing view" needs to be given that specific blog post to render.
Is it possible to get that information from the "blog post listing view" to the "blog post editing view"? Yes, b/c the "blog post listing view" knows which "blog post object" you selected.
You'll find yourself answering "no" when you have what I'd call a long-distance dependency in your user interface workflow: to get to view C from view A you pass through B, but the naive implementation of B doesn't let you pass along some needed bit of information from A to C; this is probably the single-most-common source of frustration/head-slapping when you're first learning Cocoa (or any GUI app).
Hopefully, you'll finish all this work and have found no unpleasant surprises (ie: you have exhaustively analyzed your program's workflow using the above information and all information you need can be delivered to where it is needed).
If you've got some gaps -- user interface modes that can't get information they need -- you should fix your diagram (adding extra data-items to user interfaces as-needed).
Once you're done with this you should more or less have the "Model" and "View" tiers of your application figured out -- the "model" objects are all the data model objects, and the "view" tier is all the user interface items you've made (eg: all the separate .nib files).
You can go ahead and write the data model classes and create the .nib files now.
From here, building out skeletal controllers is pretty easy: for each user interface item, you build out a controller class, making sure it has fields for each user interface element in your user interface item (eg: it has one field each for the "title" text field and the "post" text field) and one field for each data item it has to know about (eg: a "post editing view" controller has a field for a "blog post" data object).
You now have to add the actual logic to the controller. This comes in three main forms:
- you add code to synchronize the user-interface with the data item (ie: if I've got this "blog post" data item, write a method that makes the on-screen "title" field == the "title" field in the "blog post" data item, and so on)
- you add code to synchronize the data model with the user interface (ie: if the on-screen "blog post" has such-and-such title and such-and-such post, this code makes the "blog post" data item's fields the same)
- you add code for handling each "entry" and "exit" from the corresponding view (eg: one method for setting up a view to start editing an existing blog post, one method for setting up a view to start creating a new blog post, and some methods to handle closing-the-view-and-saving-your-work)
If get through with all the above, you're going to be pretty close to finished with whatever application you're writing; the last steps are dealing with stuff like the "startup" code (when the program starts, how does it bootstrap itself into a user interface state?) and similar tasks.
The above process is extremely heavyweight, and I don't pretend to use it anymore -- I might sketch out particularly-complicated parts, but not the whole app -- but I do recommend mocking up at least your first few progs with it; it's a good learning exercise, and it's a little more "obvious" than a pure "object diagram".