If you haven’t looked at part one on how to go the extra mile in AS by calling objc methods with applescript, and getting started with reading the Appkit documentation, you may want to. It’s not a requirement for this article and the following ones, but it provides some background to what’s next. Sorry for those that expected this to be posted yesterday… I went out.
So now you want to go thee next step. You’ve gotten the power of all the objc code last time, the next advantage you can gain is speed. In this we’re going to port an application completely to objc, and I’ll attempt to guide you through the steps. This article will be about how to work on your nib for objc, the next will be on writing basic handlers in xcode, and part four will cover more advanced handlers, common classes, and more.
A few final notes before we begin. This is intended to be a guide for anyone’s application. Although at first we’ll be working with basics, we’ll get to the more advanced in time. Please feel free to comment on the article, and I will try to respond to every post. As I am not paid for this, nor am I an expert all I can say is I will attempt to answer every question. Also I want this to apply to everyone’s application so I will be using very generic examples that I hope will give you the tools to combine to create your solution. Oh, and you don’t actually need to be porting an application from AS to Objc to use the information here, you could be building from scratch. If you are porting, I recommend creating a new seperate project and rebuilding everything (nib included), if your interface is very complex it may be possible to replace each script one at a time, but I didn’t do it that way, and I haven’t done much work with “mixed applications”, (ask jonn8… he has several examples that are mixed… I don’t know the issues with it, but I don’t think there are any).
So step 0 btw is to recreate your interface, dragging and dropping views, setting up their properties, anchoring and resizing stuff… and then we move into the new territory.
A) Classes
A “class” is a module of code reuse and orginization. Sounds like a script right? It’s a matter of personal taste how many scripts to use in applescript studio, but when moving to objc/Cocoa my approximate rule is, for each script I would have made, I make a class. As one grows more accustomed to working in objc, you may adjust this as your porgramming style adapts to the new language, but it’s a pretty good rule of thumb for starting.
“A class is a module of code reuse”… Like a script object in applescript a class can have many copies or “instances” and just as a script object can have a “parent” property that causes it to inherit or gain some of the properties of another script, a class is said to inherit from a superclass or to become a subclass of its superclass.
To create a class in IB most of the time we click on the “Classes” tab of the nib’s window, make sure we scroll to the left, and click on NSObject. Then in the “Classes” menu choose “Subclass NSObject” and then rename it to something appropriate* (like «appname»Controller). It is possible to subclass other objects in the heirarchy, but most of the time we just want the features provided by the generic NSObject.
*About naming: Some of this is convention (which helps your class to fit in) and some is language constraints, but it is common to name your classes as WordsSquishedTogether with the first letter capitilized and maybe prefixed with a two letter prefix that you make for the application, or for yourself. Only use the standard 26 roman letters (upper or lowercase). You may be able to use numbers… but it shouldn’t come to that. As everything else is named with the WordsJammedTogether convention, you shouldn’t switch to CAPS_WITH_UNDERSCORES like eiffel, or use underscores at all really… Not laws/rules… just conventions.
Some more terminology before we go on. A class has two parts, it’s “members” (AS: properties), and “methods” (AS:handlers). Let’s set some up right now.
B) Adding Outlets
An “Outlet” is a special kind of member (property) of a class. What’s special is that you can set up an outlet in IB, and when your nib loads, the member already is connected to the view you want it to be. No more button “add” of box “controls” of tab blah blah blah of window “main”… just addButton… It’s very, very nice. I recommend adding an outlet for every part of the interface you are going to mention in your code. Approximately one for each part of the interface you named in AS with some exceptions: you don’t need to have outlets for things like boxes and tabs unless you’re specifically going to manipulate them. This is because you don’t have to use them to get access to their subviews, you can directly make connections with them and cut out the middlemen.
To add an outlet, select your class in the classes tab, open the attributes inspector (cmd-1), make sure the outlets tab is selected and click add at the bottom. Rename it to something appropriate** and you can (a) ignore the type and leave it as “id” or (b) change it so that your addButton outlet can only be an NSButton. (Changing it makes your software more reliable, and gives IB and XCode more information so they can serve you better. Not changing it allows interesting dynamic features and saves me from talking about more than you ever wanted to know about types until part 3 or 4). (I usually type my outlets…)
**member names are usually wordsSquishedTogether, with the first one lowercase, possibly with an underscore at the beginning like _addButton or addButton
C) Adding actions
An action is a special kind of method. It’s special in that you can make connections to it in interface builder yadda yadda (see the intro to (B)…). This is for things like button clicked handlers and choose menu item handlers… The nice thing is you can have several of them rather than a single on clicked handler that has to figure out which button was clicked… (please note that this doesn’t cover the drag/drop suite, document suite, much of the application suite, nor the data view suite and possibly others… this is for “controls” that have an action, like clicked, choose menu item, action, etc. We’ll get to the rest of them in part four…)
To add them, use the same inspector as for (B) and choose the actions tab. Click add to add one and rename it as you like***. Note that IB puts a colon on the end. This signifies that it’s a method that takes a single argument. That argument is equivelent to theObject argument that gets passed to your handlers in ASS.
***about action names: like outlets in (B), wordsSquishedTogether, no underscore, they end in a colon, that if you don’t put in, IB will. eg: addButtonClicked:, remove:, doIt:
D) Instantiating your object/adding files to your project
Once you’ve added all the outlets, and actions you want to support (you can change your mind later… but that’s in part four) We need to create an instance of the class. There’s one NSWindow class, but many NSWindow instances… class is to cookie cutter, instance is to cookie… class is to template script object, instance is to copying script object and setting it’s properties… At any rate need an instance of the class to make all those connections we were getting ready to make in (B) and (C). With your class selected in the classes tab, choose the menu item “Instantiate YourClass” of menu “Classes” of the main menu(;P). You can name the instance that appears in the instances tab if you want… this part REALLY isn’t necessary though…
One last piece of house keeping is that we’re going to want to edit the code for this class so select the class again in the classes tab (double click your instance for a short cut), and under the classes menu choose menu item “Create Files for YourClass”, add the .h and .m versions to your project in the dialog that appears. We’ll be working with these files in part three.
E) Making connection
You’ve done this before if you’ve ever used an applescript data source. You ctl-drag from your object to another, select the outlet and click connect (or double click) to connect outlets. To connect actions you ctl-drag from the button or other control to your instance and select the action and click connect (or double click)…
That’s all for this time… at this point it’s pretty useless but we’ll write some action handlers next time in part three: XCode/Objc basics for ASists. I’ll try to post that tomorrow… but no promises.