Over the last couple of years I've been learning Cocoa in fits and starts, never quite progressing as methodically or consistently as I'd planned. I'm hoping this blog category will be a way to get organized. I have a few books on Cocoa, including Aaron Hillegass' Cocoa Programming for Mac OS X which I'll work through first.

I am not a programmer by trade (my background is in human-computer interaction). I did some elementary computer programming as part of my undergraduate study; and, later, a couple of C language courses through continuing studies. I've always skirted around the edges of "real" programming, from tentative dabbling with BASIC on my Apple II to pseudo-languages like SuperCard and Prograph. I've done some PHP; and I'm fairly adept at XHTML/CSS, but that's not programming.

I became frustrated with these high-level languages in that I was always dependent on the vendor to provide or add access to the areas of the operating system framework or toolkit in which I was interested. AppleScript Studio looks interesting but suffers from the same problem, even though it's from Apple. Perhaps most importantly, Cocoa lowers the barrier to entry for "real" programming; is the mature primary toolkit for Mac OS X so is very likely to survive and evolve; and is more of a "hard skill."

However, even the books written for relative novices, such as Hillegass' and Cheesman's, are missing a certain beginner perspective. I find I have a fair number of unanswered questions. There are some things that seemed to have fallen through the cracks, somewhere between assumptions about C language basics and some smaller, immediate practical applications of Cocoa. Of course, all of these books make certain assumptions about ability and prior knowledge. However, taking the C language example, I don't think it would have been difficult to have included a few simple "how and why" (or "why not") notes.

Cocoa Week 2: Conversion Methods and Data

August 22nd, 2006

Day 6: More work on the ChromaBank class. I was pondering how best to handle data for the conversion methods. I realized that, looking forward to when I get to a patch librarian and, later, an editor, this class should be able to store patch bank data in different formats simultaneously: for example, Syntech sysex; EES sysex; audio for the cassette interface; and textual data–for which I hope to do an HTML template in addition to the simple listing provided by the original tape2txt. So I’m thinking that, in converting say from sysex to tape, I should initialize with sysex data from the input file(s) and then simply ask the object for audio patch data. (This could potentially ease conversions from multiple formats simultaneously, as well: the user might drag a couple of different kinds of files to the app, with HTML as the desired final output for all.) The fact that the tape data doesn’t exist would trigger an internal conversion and return the data in the requested format. This would also be an advantage in future for saving to files owned by the application, as only the data of interest to the user would be saved; perhaps there could also be a user preference. So syx2tape becomes a method of ChromaBank, called when tape data is requested and the tape instance variable is empty, or when the sysex data has ben modified. Perhaps the designated initializer should put “scratch patch” data in the sysex instance variable and leave the others null: this will be the most useful format for most people, and is also used by the new CPU Plus instrument upgrade.

One interesting stylistic limitation I have found is that a method which calls other instance methods seems to require variables that are in the scope of the object, rather than just the method. Which seems messy. Specifically, as I write bytes to the data format I’m converting to, I have to maintain counts and the converted data object-in-progress as well. Would it be better to pass these values back and forth between methods? What is the overhead for that? Perhaps in this case I don’t have to worry about this, as I can convert straight into the tape instance variable; this would presumably work also if it was already populated with data (for instance if the sysex variable was changed and another conversion was requested–which makes me think I need to convert other existing bank formats automatically when any of the format instance variables is set, to keep all data in sync within a ChromaBank object).

Day 8: Posted a question reflecting some of the above to the Cocoa-Dev list.

Day 9: Received a thoughtful reply from Rush Manbert, who suggested that with respect to using instance variables for efficiency, “the answer in 99.999% of the cases is no.” Also, the old adage, “first make it run, then make it fast.”

Day 10-12: Started putting together method arguments for passing back and forth a conversion flag; I’m using the form wasUp = [self writePre:inputSyx withFlag:wasUp]; and it seems this will work pretty well. Trying an instance of NSMutableData with appendBytes:length for compiling the converted data, but there’s something I don’t understand about the void pointer form for the bytes themselves I have to investigate.

Another problem I’ve had is finding a Cocoa equivalent for fgetc() used in the original code. This C function gets the next character from an input stream. So I am putting the data to be converted into an instance of NSInputStream. No results yet.

Day 13: Installed the CPU Plus upgrade in my Chroma, which will make it easier (more like modern synths) to implement an editor/librarian for the instrument.

Day 14: How do you inspect object instance variables in the Xcode debugger? I’m in an instance method on the stack. Globals doesn’t show them.

Real Progress on Cocoa

August 13th, 2006

After Steve Jobs’ WWDC keynote I got itching to get going and leave the tutorials behind. After a while they become (for me) plodding and uninspiring, and I thought that I’d picked up enough to build something of my own. I decided that the keynote was Day 0 of my Cocoa work. So I started a project to rewrite David Clarke’s Chroma command line patch conversion tools in Cocoa, with a graphical user interface.

Day 1: The first thing I decided to explore was the opening of files. It didn’t take long to find that I had to set an application delegate to respond to Apple events. I created an application controller object in my NIB file and ended up using application:openFiles: (I didn’t seem to get anything from application:openFile; a subject for further exploration). Confirmed that the array received contained the paths of files dragged to the application icon. (Have to option-command drag files to the Dock icon in order for it to highlight; fooled around with the application properties and file types without success. Another thing to get back to.)

Day 2: Next I investigated NSFileHandle which provides the ability to read data from a file; I used the fileHandleForReadingAtPath: method. Successfully output file contents to the console, using the description: method.

Day 3: The most interesting progress I’ve made in these early days involves the application of MVC to my thinking and its effect even on user interface design. I was going to start by doing an application for converting Chroma sysex files to tape (audio) format: see syx2tape and syx2tape.c.

However, I realized that the app controller object shouldn’t do the conversion work: I need a patch bank object that will encapsulate the data and conversion methods, with the controller object mediating between this object and the user interface (and files). It became obvious that the ChromaBank class would be generic to all the conversions and, rather than using it across a number of applications, my application should do them all, and hopefully be smart enough to discern the format being requested for conversion (and ask the user for the destination format). So, when the user requests conversion of a Syntech sysex file, and desires a textual patch listing, the ChromaBank class converts itself from sysex to tape (the original syx2tape, which becomes a method in the class), and then does a tape2txt.

So I started on the ChromaBank class and thought about the methods, particularly initialization. It makes sense to initialize to a Chroma “scratch patch” (default sound) in sysex format. I will write that method later: perhaps the app will include a scratch sysex file in its bundle. I wrote an initializer method, initWithSysexData. Good progress in my thinking and with the code: compilation errors are a great learning tool.

Day 4: Didn’t have much time but thought about the application icon and started fooling around with IconBuilder Pro.

Day 5: Started rewriting the syx2tape routines (C) in Objective-C.

NSString memory allocation

June 24th, 2006

Working through Chapter 3 of Cocoa Programming for Mac OS X. Question: why can you do this

NSString *temp = @"this is a string";

and you don’t have to do this:

NSString *temp = [[NSString alloc] init];
temp = @"this is a string";