Category Archives: Cocoa

Adding Views to Table Views with Core Data

I’ve been working on a new Cocoa app for Scientists for a few months now. It’s brand new software, so I’ve used the opportunity to learn Core Data (CD). Recently, I discovered an interesting use for CD: adding non-control NSViews to an NSTableView.

The view I was working with was a spinning NSProgressIndicator. I basically wanted to reproduce the sort of behavior you would see in the Mail app, where the indicator would spin during a refresh. I figured this must be a pretty standard problem, and that a solution would only be as far away as my Google search field in Safari, but that wasn’t altogether true…

The problem is that NSProgressIndicator is not an NSControl, and does not have an associated NSCell, which is required by NSTableView. I did find solutions to this online, it’s just that they weren’t straightforward. For example, I found a discussion on CocoaDev that was very helpful in understanding the issues, but didn’t provide any elegant or complete solutions. The CocoaDev page did provide me with a link to a more complete example by Joar Wingfors. The code in question worked a charm, but it was far from simple, coming in at several hundred lines. Joar’s code did inspire me though, and I have now come up with a solution using Core Data that puts a spinning indicator in my table view with less than 50 lines. Here’s how.

The trick — and this is the part that doesn’t sit completely right with me — is to add an attribute for the NSView to the Core Data entity represented in the table view. My entity was called Host, and it had an boolean attribute called isRefreshing which was set according to whether data for the entity was in the process of updating. To this entity, I added a second attribute calledrefreshProgressIndictor. Importantly, this attribute was made transient, with undefined type, so that Core Data would not attempt to save the NSProgressIndicator to file.

The refreshProgressIndicator attribute gets initialized to a newly created progress indicator in one of the awake... methods of Host:


-(void)commonAwake {
    NSProgressIndicator *indicator =
        [[[NSProgressIndicator alloc] initWithFrame:NSMakeRect(0,0,16,16)]
            autorelease];
    [indicator setStyle:NSProgressIndicatorSpinningStyle];
    [indicator setDisplayedWhenStopped:NO];
    [indicator animate:self];
    [indicator bind:@"animate" toObject:self
        withKeyPath:@"isRefreshing" options:nil];
    [self setValue:indicator forKey:@"refreshProgressIndicator"];
}
	
-(void)awakeFromInsert {
    [super awakeFromInsert];
    [self commonAwake];
}
	
-(void)awakeFromFetch {
    [super awakeFromFetch];
    [self commonAwake];
}

Note also that the animate binding of the progress indicator gets bound to the isRefreshing attribute of the Host. That way, whenever the isRefreshing attribute changes value, the progress indicator will immediately be informed by KVO, and start/stop spinning as appropriate.

I don’t feel good about adding a view like NSProgressIndicator to a model class; it messes with MVC, and disturbs me somewhat. But the solution it leads to is elegant, and given that the attribute is transient, I am able to live with it. How about you?

We now have our progress indicators, one for each Host. The next question is: How will they get displayed in the table view? Not surprisingly, we need some sort of cell. The code for this is extremely minimal. Here is the interface


@interface ViewCell : NSCell {
    NSView *view;
}
	
@end

and here the implementation


@implementation ViewCell
	
-(void)setObjectValue:(id )object {
    view = (id)object;
}
	
-(void)drawInteriorWithFrame:(NSRect)cellFrame
    inView:(NSView *)controlView {
    if( [view superview] != controlView ) {
        [controlView addSubview:view];
    }
    NSSize viewSize = [view frame].size;
    float dx = 0.5f * (cellFrame.size.width - viewSize.width);
    float dy = 0.5f * (cellFrame.size.height - viewSize.height);
    NSRect viewFrame = NSInsetRect(cellFrame, dx, dy);
    [view setFrame:viewFrame];
}
	
@end

The ViewCell assumes that the object passed to it will be the view that will appear in the table view. As the name suggests, it is not specialized to progress indicators, but should work with any NSView. When the table view draws a cell, it first calls setObjectValue. The ViewCell stores the object passed in the instance variable view for use later in the drawing methods.

The drawInteriorWithFrame:inView: method is called to actually draw the cells contents. In this case, rather than do that, the view is added as a subview to the control view passed in. That way, when the progress indicator is redrawn, the control view will also redisplay, and we will end up with an animated progress indicator, rather than a static image.

The ViewCell does not resize the view passed in drawInteriorWithFrame:inView:, but does position it in the center of the cell frame. Variations on this approach are possible, of course, and will depend on your objectives.

The ViewCell is typically created and added to the table view in the awakeFromNib method of anNSArrayController class.


-(void)awakeFromNib {
    [super awakeFromNib];
    NSTableColumn *col =
        [hostsTableView tableColumnWithIdentifier:@"refreshProgress"];
    [col setDataCell:[[[ViewCell alloc] init] autorelease]];
}

All that’s left is to bind the table column in IB to the refreshProgressIndictor attribute of the Hostentity via the arrangedObjects property of the NSArrayController. Once that’s done, theNSProgressIndicator views will be delivered to the setObjectValue: of the ViewCell, and we can conclude that some progress has been made.

Leave a Comment

Filed under Cocoa

Joining the MacResearch Team

I’ve been a regular visitor to the www.macresearch.org web site pretty much since its inception, so I was very pleased to be able to accept an invitation to join the Executive Committee.

MacResearch is a web site that targets the Mac-using Scientist. It provides a wide range of services, including news feeds, software reviews, how-to articles, forums, a script repository, and — most recently — access to a 4-node Xserve computational cluster.

But one of the more important roles that MacResearch has taken on is that of mediator: Polls are held regularly, and the results summarized in a report which is communicated directly to Apple, and released to the community at large. If you want to know more, either visit the site, or check out the new web cast, in which Ivan Judson and Joel Dudley explain it all much more eloquently than I ever could.

What will my role be at MacResearch? To be honest, it’s a bit too early to say. I will certainly contribute content, most probably related to scientific software development in Cocoa, Python, C++, and Fortran. I also have some ideas for applications of Xgrid, but I can’t say much more than that until I find out what the existing MacResearch team have in mind. Whatever happens, I’m sure it will be an interesting ride…

Leave a Comment

Filed under C++, Cocoa, Fortran, Mac, Personal, Python, Scientific Programming

launchd and Growl for a Cleaner Desktop

I am one of those people that lets things accumulate on their desktop until there is literally no space left, before resigning to a clean up. (This applies equally to my physical desktop as my virtual one.) I finally decided I needed to do something about it, and resolved to leverage two technologies that are relatively new to me: launchd and Growl.

I have known about launchd since its introduction in Tiger, but haven’t had an excuse to use it yet. My plan was to use launchd in its cron-like mode to run a cleanup script once a day. The cleanup script would search for old files and directories on the desktop, and simply move them to the Trash. As a nice touch, I decided to use Growl to notify me when the script had run, with a message detailing how many files and directories had been moved. If you aren’t familiar with Growl, I have just one piece of advice: get familiar. It is a very cool user notification system.

I began with the script, which I called cleandesktop, and added to my ~/bin directory. This is what it looks like:


#!/bin/sh
	
numFiles=`find ~/Desktop -fstype local -type f -maxdepth 1 \
  -ctime +3 | wc | awk '{print $1}' 2>&1`
find ~/Desktop -fstype local -type f -maxdepth 1 \
  -ctime +3 -exec mv -- {} ~/.Trash \; >/dev/null 2>&1
	
numDirs=`find ~/Desktop -fstype local ! -name . -type d -maxdepth 1 \
  -mtime +3 | wc | awk '{print $1}' 2>&1`
find ~/Desktop -fstype local ! -name . -type d -maxdepth 1 -mtime +3 \
  -exec mv -- {} ~/.Trash \;  >/dev/null 2>&1
	
/usr/local/bin/growlnotify "Desktop Cleanup" <<eor
$numFiles files and $numDirs directories were moved to the trash.
eor

This script is basically a number of find commands. Each command has many options, which I based on commands in Apple’s /etc/daily script that is used to clean the /tmp directory. Two of the commands are there just to count files and directories, and the other two do the actual moving. Files and directories are moved to trash after not being accessed for three days; I figure this gives me enough time to move anything I want to keep to a safe place.

Growl comes into it in the last few lines. The growlnotify command allows you to produce notifications from the command line. The title of the notification is given as an argument, and standard input gives a detailed description. In this case, I have reported the number of files and directories moved in the description.

To make the picture complete, I added the following content to the file~/Library/LaunchAgents/DesktopCleanup:


<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE plist PUBLIC "-//Apple Computer//DTD PLIST 1.0//EN"
"http://www.apple.com/DTDs/PropertyList-1.0.dtd">
<plist version="1.0">
<dict>
	<key>Label</key>
	<string>net.macanics.desktopcleanup</string>
	<key>ProgramArguments</key>
	<array>
		<string>/Users/drew/bin/cleandesktop</string>
	</array>
	<key>LowPriorityIO</key>
	<true/>
	<key>Nice</key>
	<integer>1</integer>
	<key>StartCalendarInterval</key>
	<dict>
		<key>Hour</key>
		<integer>20</integer>
		<key>Minute</key>
		<integer>15</integer>
	</dict>
</dict>
</plist>

This causes the cleandesktop script to be invoked a 20.15 each day. To load it the first time, without logging out, I used this command:


launchctl load ~/Library/LaunchAgents/DesktopCleanup
launchctl start net.macanics.desktopcleanup

And with that, I may finally be able to make out the Tiger on my desktop … or is it a Panther? Puma? It’s been a while…

Update

After more testing of this approach, it seems that using the -atime option in the find commands leaves a lot of files on the desktop that should be removed. I have now removed these above and in my own scripts, leaving only the -ctime option. This seems to work a lot better.

Leave a Comment

Filed under Cocoa, Mac

Psychic Mac

I just had one of those spooky moments. You know the ones: you are debugging, and find something totally unexpected…something that shouldn’t even be possible.

What I was doing was running a subprocess from within a Cocoa app I am developing. I was usingNSTask to start a script, and retrieving the output with an NSPipe. Nothing complicated about that.

Because I am still in the early stages of development, the script I was using was just a stand-in, to make sure everything was working to plan. It simply wrote a property list to standard output, with a few static values in it. I was planning to rewrite this script later such that it invoked the UNIX command ps, to get information about tasks running on the computer.

To my utter surprise, when I ran the application and examined the script output in the debugger, I saw this:


  PID  TT  STAT      TIME COMMAND
  711  p1  S+     0:00.20 -bash

Hmm, that looks nothing like my property list, and, what’s more, it looks awfully like the output format of the ps command! A quick search of my project revealed no reference whatsoever to ps. What was going on? Was my Mac psychic? Did it know what I was going to do next?

As with many of these ‘How could it be so?’ debugging moments, the answer turned out to be relatively simple, but it had me spooked for a while. When I initially created the script, I hadinserted a ps command into it, but had quickly forgotten that I had done this, because I then changed the script to print the property list. The script file resides in a directory that is copied into the Resources folder of the application bundle when the app is built. The problem seems to have been that Xcode did not recognize that the script needed to be recopied into the application when it was modified. A clean build fixed the problem.

The moral of the story: when confronted with something you don’t understand, your first instinct is to ascribe it to some supernatural power, when the more likely explanation is just that Xcode is buggy.

Leave a Comment

Filed under Cocoa, Mac, Scientific Programming

More Experiences of “The Life”

Luis de la Rosa is blogging about his first encounter with “The Life”, programming full-time for himself. It is a nice follow-up to my blog on “The Life” from a while back.

Leave a Comment

Filed under Cocoa, Mac

Not livin’ “The Life”, and lovin’ it!

Dan Wood has written an interesting entry in his blog about how the logo for his company Karelia came to be. He uses this to dive into a history of Watson — probably the first Mac app to bring web services to the desktop — and his latest project, a WYSIWYG web site editor called ‘Sandvox’.

The Sandvox Story

The main motivation for the story was a rumor: someone spotted a link to a yet undisclosed piece of software on Apple’s web site called ‘iWeb’. Apparently it was posted by accident, and quickly pulled, but not before the damage was done. Dan is clearly worried that iWeb will be a direct competitor to Sandvox, and I’m afraid he is probably right.

As Dan explains, if iWeb is indeed a competitor to Sandvox, it is the second time he has been struck by Apple-flavored lightening: After establishing the market, Watson soon found itself in the ring with Sherlock 3, which bore an uncanny resemblance to Karelia’s application. Watson survived for a while longer, but eventually went the way of the dodo.

Karelia’s logo shows a small human-powered railway car; it was motivated, according to Dan, by a conversation he had with Steve Jobs just before Sherlock 3 was released. Jobs apparently told Dan that Karelia was a hand-powered rail car, and Apple was the locomotive that owned the track, and was bearing down fast. It’s a very amusing story.

Dan has since moved on, and is in the last stages of development on Sandvox. (Starting today you can download a public beta.) So the news that Apple may again be encroaching on his territory is undoubtedly a bit of shock.

Today I downloaded the Sandvox public beta, and played with it for a little while. It is a very nicely written piece of Cocoa software, and I have no doubt that it would do extremely well … if Apple were not to enter the race. If iWeb is similar in functionality — and worse still — bundled with iLife, Sandvox could be dead in the water before it even gets started.

To be honest, I don’t know how much it should really come as a shock. Sandvox reminds me a lot of Apple’s Pages and Keynote software, with the primary difference being that Sandvox is targeted at web site development. It shouldn’t come as too much of a surprise that Apple might consider developing a Pages-like app for creating web sites. Yes, Karelia may be about to be struck by lightening a second time, but that could have to do with the fact that they appear to be leaning against a flagpole in the middle of a golf course.

The Development Tightrope

If you are going to play with the big boys, there is always the risk of getting burned. It’s happened time and time again. The payoffs of writing mainstream apps are great, but the competition is high. Even if you have a unique idea, and have the market to yourself, its success may ultimately be its downfall, because it won’t go unnoticed. You had better make your money fast, because it won’t be long before you have company.

If you are really serious about making money writing Cocoa apps, I think you can learn a lot from guys like Wil Shipley. Delicious Library is mainstream enough to make a heap of cash for Mr Shipley, but perhaps not mainstream enough that it would be of interest to Apple. Apple are in the business of very high-volume software — stuff that everyone needs. Browsers, photo management software, digital duke boxes, etc, etc. Delicious Library is useful to many people, but not everyone. I don’t think it would make business sense for a company the size of Apple, but for a small company like Delicious Monster, it’s a cash cow.

The Life

Developers like Wil Shipley, Dan Wood, and Brent Simmons (of NetNewsWire fame) are highly respected members of the Cocoa development world. Cinderella stories of programmers that have developed killer apps in their spare time, quit the day job, and started living ‘The Life’, always make a great read for aspiring developers. In the beginning, I was no different, but my outlook has changed. I actually don’t want my software to be too successful.

See, the thing is, I like my day job. I don’t want to quit it, even if it meant I could develop Cocoa apps all day. I like working with Cocoa as a hobby, but I don’t think I would like it nearly as much if it dominated my every waking hour.

Not only that, but as your sales increase, the amount of time you have to spend on the business side of things increases. Eventually, you have to take on staff to help with administration and/or support, and that comes out of your income. With limited sales, you can do everything yourself, and the revenue goes straight into your personal bank account.

Niche Markets

The point is, there is a third way: writing niche software. It won’t make you rich, but you can make some nice pocket money without the stress of running a business. If you actually like your day job, this might be the way to go. Just make sure you don’t write anything that becomes too popular.

Trade Strategist is the Cocoa software that I develop and sell. It is financial modeling software for the stock market, and the potential market is actually very small. Nonetheless, I do make some reasonable pocket money out of it, ranging between $500 and $1500 a month, depending on the release schedule. I won’t be getting rich any time soon, but the $10000 or so I earn per year from Trade Strategist does come in handy. It’s just paid for my new bathroom, for example.

There is more than one way to skin a cat: You can take the high-risk, high-rewards route of Karelia, or you can just play in the minor leagues. You won’t ever be Donald Trump, but it can still be very rewarding, and you’ll even be able to sleep at night. Here’s to hoping Dan can get some sleep before tomorrow’s keynote.

2 Comments

Filed under Cocoa, Mac

Enums Keep Popping Up

One of the best ways to learn is to learn from the mistakes of others — it sure beats making your own. Recently, I got that sinking feeling that comes from realizing that you have made a colossal error of judgment, and are going to have to jump through hoops to correct it. What follows is the story so far, in the hope that others may learn from my ignorance.

The tale revolves around the financial modeling software that I develop in my spare time: Trade Strategist (TS). In one particular application window, I have utilized a number of Pop Up Buttons; each button is mapped to an instance variable in a model class, with each item in a button representing a different discrete state of the variable. There is nothing unusual about this at all.

The problems began when I started to incorporate Cocoa Bindings into TS, and decided that because the content values of the Pop Up Buttons were likely to change from time to time, I would like to be able to stipulate the different options entirely in code, rather than Interface Builder (IB). The reasoning was that I would have a better overview of all the different internal states and their labels if everything was defined close together in the program. The alternative would have been to update the Pop Up Buttons in IB by hand each time an option was added or changed. This would not have been the end of the world, but I thought my approach — in which the state labels were effectively treated as data in the model layer — was easier to oversee.

I began by defining static NSString variables for the different labels in each NSPopUpButton, and methods in my controller class to return the values with which to populate each button. I bound one of these methods to the contentValues binding of each pop up. To complete the picture, theselectedValue binding of each button was bound to an NSString instance variable in a model class. Voila!

Unfortunately, I only realized the error in my ways after a version or two of TS had passed. I was representing states internally with the same NSStrings that were used to represent the option in the user interface. Not only is this quite inefficient in memory terms, it is also extremely inflexible. If you want to change the wording of an item in a Pop Up Button, you also have to update unarchiving methods like initWithCoder:, even though the model hasn’t actually changed. It is a classic example of compromising the Model-View-Controller (MVC) doctrine.

To solve the problem — while preserving the ability to define item labels in-code — I introduced a few classes for mapping enum values to NSStrings. The appropriate form for a variable representing a discrete state in the model layer is an enumerated type (i.e. enum); a common way to represent a discrete state in the user interface is a Pop Up Button. These two entities are often used together, and it seems logical to have a simple way of mapping the values of one to the other.

The first class I defined was EnumValueLabel. This simply stores an enum value, and its associatedNSString label:


@interface EnumValueLabel : NSObject {
    int enumValue;
    NSString *label;
}
	
+(id)enumValueLabelWithValue:(int)val andLabel:(NSString *)label;
-(id)initWithEnumValue:(int)val andLabel:(NSString *)label;
	
- (int)enumValue;
- (NSString *)label;
	
@end

The EnumValueLabels are aggregated in the LabeledEnum class:

@interface LabeledEnum : NSObject {
    NSArray *enumValueLabels;
}
	
-(id)initWithEnumValueLabels:(NSArray *)labels;
	
-(NSArray *)enumValueLabels;
	
-(NSArray *)enumValues;
-(NSArray *)labels;
	
-(int)enumAtIndex:(unsigned)index;
-(NSString *)labelAtIndex:(unsigned)index;
	
-(int)enumWithLabel:(NSString *)label;
-(NSString *)labelForEnum:(int)en;
	
@end

The idea is that you initialize a LabeledEnum for each enum that you want to map to aNSPopUpButton. In the following example, a class method initializes and returns a LabeledEnumcorresponding to the enumSignalType.

typedef enum _SignalType {
    BUY_SIGNAL           = 100,
    HOLD_SIGNAL          = 200,
    SELL_SIGNAL          = 300,
    SELL_SHORT_SIGNAL    = 400,
    COVER_SHORT_SIGNAL   = 500
} SignalType;
	
...
	
+(LabeledEnum *)signalTypeLabeledEnum {
    static LabeledEnum *le = nil;
    if ( !le) {
        le = [[LabeledEnum alloc] initWithEnumValueLabels:
            [NSArray arrayWithObjects:
            [EnumValueLabel enumValueLabelWithValue:BUY_SIGNAL
                andLabel:@"Buy"],
            [EnumValueLabel enumValueLabelWithValue:HOLD_SIGNAL
                andLabel:@"Hold"],
            [EnumValueLabel enumValueLabelWithValue:SELL_SIGNAL
                andLabel:@"Sell"],
            [EnumValueLabel enumValueLabelWithValue:SELL_SHORT_SIGNAL
                andLabel:@"Sell Short"],
            [EnumValueLabel enumValueLabelWithValue:COVER_SHORT_SIGNAL
                andLabel:@"Cover Short"],
            nil]];
    }
    return le;
}

These classes are only really useful when they are combined with the third class:EnumValueLabelTransformer. This is a subclass of NSValueTransformer, and is used to bind theselectedValue binding of the NSPopUpButton to the enum instance variable in the model class.


@interface EnumValueLabelTransformer : NSValueTransformer {
    LabeledEnum *labeledEnum;
    NSMutableDictionary *enumValuesForLabels;
    NSMutableDictionary *labelsForEnumValues;
}
	
-(id)initWithLabeledEnum:(LabeledEnum *)labeledEnum;
	
-(LabeledEnum *)labeledEnum;
	
@end

You construct one EnumValueLabelTransformer for each enum, in the application delegate’s initializeclass method:


+(void)initialize {
    [NSValueTransformer setValueTransformer:
        [[[EnumValueLabelTransformer alloc] initWithLabeledEnum:
            [self signalTypeLabeledEnum]] autorelease]
        forName:@"SignalTypeValueTransformer"];
}

The contentValues binding of each Pop Up Button can be bound to a method like the following:


-(NSArray *)signalTypeLabels {
    EnumValueLabelTransformer *trans = (EnumValueLabelTransformer *)
        [NSValueTransformer valueTransformerForName:
            @"SignalTypeValueTransformer"];
    LabeledEnum *en = [trans labeledEnum];
    return [en labels];
}

With all of this apparatus in place, it is possible to define your instance variables as enumerated types, and assign them labels in code. The EnumValueLabelTransformer converts the enum values to the NSStrings that populate the NSPopUpButton. Note also that separation of model and view is now reinstated, because the item labels in the button can be varied independently of the model classes.

I am releasing the three classes described above into the public domain. You can download the source code here. As you might expect, it comes with no warranty whatsoever, and the complete freedom to do with it as you will.

I am also interested in hearing how other people handle the Pop Up Button-Enumerated Value correspondence. Do you just manually enter values in IB? Or have I missed something obvious already in Cocoa? Enter a comment below, and we might all learn something…

Followup:

After writing this piece, it occurred to me that although the solution I have developed is suitable to my circumstances, it is not advisable in general. In particular, because I chose the wrong route initially, the EnumValueLabelTransformer class helps me to easily transform the NSStrings to enumvalues in the initWithCoder: method. However, if you have not made the same mistake, it is not necessary to introduce the classes discussed above, because they basically duplicate functionality already present in the NSPopUpButton class.

So how should you couple an enum to a NSPopUpButton? The most obvious way is simply to manually enter pop up items in IB, and assign a tag to each corresponding to the enum value represented. If, like me, you would prefer to define the labels in source code, you can add items to theNSPopUpButton programmatically, in an awakeFromNib method, for example:


-(void)awakeFromNib {
    [popUpButton removeAllItems];
    [popUpButton addItemWithTitle:@"Buy"];
    [[popUpButton lastItem] setTag:BUY_SIGNAL];
    [popUpButton addItemWithTitle:@"Sell"];
    [[popUpButton lastItem] setTag:SELL_SIGNAL];
    ...
}

In this case, you make no use of the contentValues binding, as was the case in the solution presented above.

Leave a Comment

Filed under Cocoa

Why developing scientific apps for the Mac is a dead end street

MacResearch, which I think is a great site for the Mac using Scientist, has pondered the question of why there hasn’t been a boom in Scientific Software exclusively for the Mac. The assumption is that because the Mac has free developer tools; a great application development interface (API) in Cocoa; and easy to use scripting languages like AppleScript, that it should only be a matter of time before a number of ‘killer’ scientific apps appear.

As a Mac-using Scientist and Developer, I am quite well credentialed to offer some insight into this. In my day job, I help develop the commercial cross-platform Quantum Chemistry softwareADF, and in my spare time I develop and sell a financial-modeling app — written in Cocoa — called Trade Strategist. I also do most of my Scientific Research on the Mac, with the free Xcode tools referred to in the MacResearch article.

There are two ways in which a Scientific App could become publicly available: The first is via a company, and the second is via a Scientist. But the Mac market is relatively small, and the market for scientific Mac users even smaller. There really is not enough money in it to support a company developing exclusively for the Mac. In fact, there really isn’t enough money in Scientific Software to afford the luxury of any platform exclusivity whatsoever. Most companies I know support multiple platforms to make ends meet.

So if we assume that a company must develop cross-platform Scientific Software, it is pretty clear why there are not many company-developed apps written in Cocoa — Cocoa is a proprietary technology only supported on Mac OS X. As wonderful as it is, it is not an option for most companies, that end up choosing cross platform solutions like Qt and Tcl/Tk.

With companies out of the running, why aren’t there more software packages coming from the Scientists themselves? Ultimately, it again comes back to money, or at least time (which equals money). Even with a great API like Cocoa, developing good software is quite a time-consuming process. To get to first base is actually quite easy: You can throw together a prototype or version of your software with limited-functionality in a few days or weeks. The problem is taking the next step of turning that unpolished rock into something desirable to others.

Writing documentation, thorough testing, generalizing the functionality, improving the user interface; it all takes a lot of time. And its time the average Scientist doesn’t have to spend on such frivolous activities. Publish or perish, man! That great user interface won’t result in any new publications, so just take the ugly but functional version of the app that you already have, use it to generate your own scientific results, and leave the swarming masses to their own devices.

I am actually talking from experience here, because I once had stars in my eyes, and a piece of software that I thought could revolutionize the Scientific World: Dynasity. Dynasity is a Cocoa visualization app. I like to think of it as a visual multi-track recording studio. You create different visual tracks, and follow them in time. Dynasity also leverages QuickTime, making it possible to capture movies and stills with the click of a button.

So where is Dynasity? Where can you download it? Well, you can’t really. Dynasity is developed and used internally in my research group, but it has never been released to the public. The time required to generalize the software for a mass audience, and the problems of supporting it thereafter, make it undesirable. And any potential sales would hardly compensate the investment of time demanded. (If you are really intrigued about Dynasity, you can download it here. Note that this is not an official release, and comes with no promise of support or any warranty whatsoever.)

There are Scientific Apps available on the Mac, but they are often a bit underdone, for the reasons given above, and could hardly be classified as ‘killer apps’. There are exceptions though: As MacResearch mentioned in their piece, Mek&Tosj — fellow inhabitants of Amsterdam — write some great Cocoa software for Molecular Biologists. DataTank is also a Mac-exclusive that I like a lot; it is a visualization app like Dynasity, but much further developed.

One thing you could be forgiven for thinking from all of this is that the Mac is not much good to the Scientific Developer. Nothing could be further from the truth. I do most of my development work, from legacy Fortran to advanced C++ and Python scripting, with Apple’s free tools on a Mac. Xcode is great, and if you add to that Xgrid, gcc, and scripting languages like Python, Perl, Ruby, and Tcl, you have a winning combination. I also regularly use TextMate, an editor gaining favor with developers, and exclusive to the Mac.

In conclusion, the Mac is an insanely-great Scientific Platform, but don’t hold your breath for Mac-exclusives in the Scientific Realm. There simply isn’t the market for the big boys, and most scientists have better things to do with their time than writing help pages and answering questions of the form “I haven’t looked at the help pages yet, but can you tell me how to … ?”.

3 Comments

Filed under Cocoa, Mac, Scientific Programming