Cocoa Noob Pitfalls
I just finished writing my first iPhone app. I have a background in Java, C++, Python, and a smattering of other programming languages on Linux and Windows in both embedded and desktop environments, so that hopefully explains my brain damaged context.
Here are the pit falls I stumbled upon while climbing up the Cocoa learning curve:
Retain/Release Memory Leaks
It wasn’t immediately obvious to me that adding an NSObject pointer to an NSMutableArray (and other containers) would actually increment the NSObject’s retain count. Not knowing this right away, I got into the (bad) habit of double-retaining objects. It took some investigation to find out what was happening, and thanks to Apple’s ingenius profiler and analyzer, I was able to identify the problem. After learning this, I came to find out that, by convention, lots of containers do this, but it’s not too apparent from the documentation.
No Container Static Type Checking?
Apple provides several container classes, including NSArray, NSDictionary, and several others. Much like old versions of Java (like the Java 1.3 stone age), you are free to add instances of any NSObject* child class. As a result, it’s possible to end up with objects of types you did not expect, and the compiler cannot prevent you or even warn you about this.
Sub-Class Insanity
It seems you have to sub-class to do very basic things, like adding items to a UIPickerView. I would have expected a trivial method call to do something like this.
Verbose Names
Stuff like appending one string to anoher is usually pretty trivial and terse in most languages. For example, in C++, you might see this:
myString += "suffix";
But in Cocoa, it looks like this:
myString = [NSString stringByAppendingString:@"suffix"];
That is a seriously verbose method name. If you count, it uses the word “String” 3 times, and that’s not even counting my variable name.
No Static Function Checking
Because Objective-C’s message-passing system is evaluated at runtime, the compiler won’t complain (much) if you try to send a message to an object that does not respond to that message (i.e., like calling a member function in C++ that does not exist). The compiler does warn you, but it will compile, run, and fail with a run-time exception. Some people consider this an advantage of Objective-C, so I can’t hold it against Apple (Smalltalk fans, I’m looking at you).
Bogus Compiler Warnings
If I define a couple messages like this in my class, without putting them in the .h file:
-(void) foo { [self bar]; // compiler warning here } -(void) bar { }
The compiler will issue a warning, even though this is perfectly safe and will run without exceptions. The compiler is apparently very eager to warn you about this perfectly safe usage, and yet still allows you to send messages that definitely won’t be responded to at run time.
Weird Autorelease Pool Crashes
The first time I misused the autorelease message, I discovered that my application would crash in the event loop processing context. The stack gave no indication where I had gone wrong, because it contained none of my own code. The autorelease pool object itself would crash because it was calling release on an object that had already been freed. The runtime exception was so counter-intuitive that I ended up reverting my code (using git) back to a prior state. I eventually isolated the cause of the problem to my misuse of autorelease, which prompted me to do a more thorough exploration of the feature. Now I recognize those kinds of crashes for what they are, but the first time I encountered it, I was confused for a while before I figured it out.
Managing Multiple Sub-Views
If you have multiple UIPickerView sub-views within your view, managing their contents can be difficult. This is because you have to write a class to implement the UIPickerViewDataSource protocol, which is usually easiest to do right inside your view controller. However, when you add a second or third UIPickerView sub-view to your view, it gets difficult to manage. The UIPickerViewDataSource protocol sends you a pointer to the UIPickerView so you can keep track of which one is which, but it just feels cumbersome. I ended up using this guy’s code to make it easier.
Permissive Compiler Stuff
The Objective-C compiler will allow you to do this:
NSMutableDictionary *myDictionary = [[NSDictionary alloc] init];
I would expect it to work the other way around, but not this way. This leads to runtime exceptions when you try to add an element to “myDictionary”, which can be surprising until you realize you have an instance of an immutable NSDictionary. The runtime exception is pretty vague too: All you get is “invalid selector”.
Disappearing Outlets
If you connect an outlet or action in Interface Builder and then later delete the outlet or action object in your Objective-C code, you will get a very cryptic error when you try to instantiate the view:
'NSUnknownException", reason: "[<uiview 0%48a3e0> setValue:forUndefinedKey:]: this class is not key value coding-complaint
What it should say is “This xib file is trying to reference item ‘foo’ which does not exist”
Working with UINavigationController
UINavigationController can only have one delegate, even though all it does is notify the delegate when the current view changes. If you want to notify more than one view controller that navigation has moved, then you have to do some juggling to save and restore the UINavigationController’s delegate. It should be easier to notify interested parties when navigation changes.
Good Stuff
Cocoa has a lot of good stuff about it too. Here are some of the highlights from my experience:
Consistent Time Units
Times are always expressed in seconds (and fractions of seconds) instead of having to guess whether it’s seconds, milliseconds, or something else. This is extremely gratifying having come from a world where you pretty much always have to guess (although Google Go’s concept of typing is still far superior).
Analys and Profiling Tools
The X-Code 4 analysis and profiling tools are excellent. I mostly learned how retain/release worked by following the memory leaks that the code analyzer told me about. It even draws little arrows on your code to show you the code path you screwed up. Also, the memory leak finder is fantastic. It shows you when your application leaks, and where each leaked object was originally allocated. This made it trivial to track down and fix my memory leaks.
Easy Animation
Animation is as easy as giving a view a destination size and position, and telling it to go. Animation is integrated into the very core of Cocoa, and it is both easy to use and beautiful on screen.
Conclusion
So there you have it. Cocoa has some pitfalls and some good stuff. That’s all I have to say about it.
2 comments to “Cocoa Noob Pitfalls”
Re: Animation – in Qt it’s pretty much the same :)
Kuba, I can’t tell if you’re joking.