Crappy Cocoa

About nine months ago, I wrote about my fairly tepid first impressions of Cocoa and/or Objective-C. At the time, I had had my first brush with the language/framework, and disliked some parts while I liked others. Now, months of experience later, I’ve come to a slightly different verdict: I’m not very impressed. In fact, I’m rather unimpressed.

There are a lot of things to like, of course — but the things to dislike are so fundamental, that the whole development environment appears broken to me.

Now that’s a rather bold statement… and not very specific either. So let’s get into the nitty-gritty of things.

Cocoa vs. Objective-C

First off, I’ve got to admit that I’m not entirely sure where to draw the line between the language and the Cocoa frameworks.

Judging by the NS-prefixed names of most of the Foundation symbols, a lot of functionality dates back to pre-Cocoa times, namely to NeXTSTEP. But while that makes a lot of the APIs old1, that doesn’t mean they’re part of the language itself.

I’m not sure if Objective-C actually encompasses such a thing as a standard libary. But given the NeXTSTEP legacy, I have a tendency to count the NS* symbols as such.

Part of the problem is that — at least in Objective-C 2.0, which is really what I’m talking about — NS* symbols and apparent language features are rather strongly tied together. For example, any string literal prefixed with an @-sign, such as @"Hello, World" becomes an NSString object.

Message Sending

In my previous article, I professed not to understand why Objective-C insists on the “message sending” terminology rather than the “function call” terminology. I knew it’s linked to the OOP model Objective-C inherited from Smalltalk, but I wasn’t entirely sure what that meant.

The difference to programming languages such as C++ is that whether or not the receiver of a message actually implements a corresponding function is resolved dynamically at run-time. In other words, the following code snippet compiles (even if with a warning message):

@interface MyObject : NSObject
// ...
MyObject * obj = [[MyObject alloc] init];
[obj foo]; // warns that foo is not defined, but compiles

Now that in itself is actually a fairly powerful thing — potentially slower than the compile-time resolution of symbols, but not the worst idea. I stand corrected: I do know why Objective-C “sends messages” now.

NSThread and NSRunLoop

Let’s quote from Apple’s NSRunLoop docs:

An NSRunLoop object processes input for sources such as mouse and keyboard events from the window system, NSPort objects, and NSConnection objects. An NSRunLoop object also processes NSTimer events. (…) Each NSThread object, including the application’s main thread, has an NSRunLoop object automatically created for it as needed.

In other words, a Cocoa application is essentially one loop2 that runs a couple of things, over and over again. One of the things it’ll do is free released objects (more on that in a moment), and — at one point or another — run a function that handles UI input of some sort. And that’s where your code comes into play, because it’ll usually be here that you start your own code.

One of the implications of this is that as long as you’re in on of your own functions, the current thread’s NSRunLoop is blocked, and cannot process any of the things it’s supposed to process. One of the strongest implications is that you cannot use a C function such as sleep() in your code, as it’ll freeze up the user interface.

Sleeping may in itself not be that big an issue. There are alternative functions that don’t block the run loop, for example. But a far more pressing concern is that you can’t perform more generic “wait until something happens” operations either3. More specifically, multi-threaded software, locks and conditions suddenly become very complicated indeed4.

If you want to break out of this jail, you can always yield to the current thread’s NSRunLoop whenever you need. The runMode:beforeDate: message runs the current NSRunLoop once, for example.

  1. Well, not old as such. By UNIX standards, they’re babies. []
  2. Or more if you spawn more threads, but let’s ignore that for now. []
  3. With sleep(N) translating to “wait until N seconds elapsed since the start of the function”. []
  4. Granted, in OS X 10.5 Apple added NSLock and NSCondition, which essentially implement the behaviour I’m thinking of. But it took a while for something this basic to arrive, didn’t it? []
  • Timo

    This is a very good read! Might help if I get the chance to dive into this stuff in the next months… ;)

    • unwesen

      Thanks! I’m glad it’s helping someone… you really need to finish your UI library you know? As a decent alternative, I mean.

  • Shrimpy

    I thought, well thats sad that you didn’t like your cocoa.

    I love hot chocolate myself :)

    • unwesen

      Shrimp! No, I love hot chocolate!

      Cocoa is Apple’s interface you use when you program for the Mac. And it’s very similar to what you use when you program for the iPhone, though that’s got a different name. So, yeah, different cocoa :P

  • Nirneve

    Sorry, but I must confess, I don’t know who you are. Must be long ago that we’ve met cause I haven’t been in contact with Franzi for years…

    • unwesen

      Well, we didn’t meet very often anyway, so it’s hardly surprising you don’t remember me. I used to teach Franzi maths. We met occasionally on parties, and I worked in the kinderdorf just below your mum’s house for a while.