Torsten's Official Cocoa Style Recommendations

I know quite a lot of people who are into Cocoa, especially just starting right now, and they don’t know yet what is right or wrong. So to help them, I thought I’d write down some of the basic rules that I follow while developing, so that they could copy them and declare me their god and master.

Wil Shipley is God

Wil Shipley has been doing development on Cooca since before it was called that way, and [his apps][deliciouslibrary] rock. There aren’t many people with more or at least just as much experience, and the cool thing is that he is willing to share this experience freely. Take advantage of this!

So read http://www.wilshipley.com/blog/labels/code.html. All of it. Then read it again. Don’t stop until you’ve understood it. Print it out. Use it as a bookmark. Stick it on your refrigerator door. Hang it in a picture frame up above the mantel where you’ll see it for sure. Yes, a simple link to someone who knows more than me is quite anticlimactic for “my magic rules”, but this is actually the most important part. Don’t skip this and read the rest — if you’re in a hurry, read this and skip the rest. This is more important than the one new feature you could implement right now.

Now, let’s get on with my recommendations. Many just expand on the guidelines he pointed out or explain my ideas of how to apply them, but it’s making my life easier to follow them, so you might be interested.

Write for Mac OS X 10.5

There are many people who still write code for 10.4 or even 10.3. They think it’s great that older users can use their stuff as well. I don’t think so. First of all, you have to have a 10.4 and, if you support 10.3, a 10.3 installation as well somewhere, and you have to thoroughly test each release on both, in addition to 10.5. You’ll also loose out on many truly great features, such as Objective-C 2.0 and garbage collection.

Of course, I don’t mean don’t use anything other than 10.5 ever. Use whatever is the latest release. Either way, the rest of this list assumes that you are using 10.5 or better.

Use Properties.

Properties are great. Whenever you have a setSomething: or even just a plain -(id)something, make it a property. Turn

@interface MyObject : NSObject
{
    [...]
}
- (void)setSomething:(id)newSomething;
- (id)something;

- (id)readonlySomething;
@end

into

@interface MyObject : NSObject
{
    [...]
}
@property (retain) id something;
@property (readonly) id readonlySomething;

@end

Why? Because it’s less code, and less code is better than more code. It also makes it plain and obvious that this is a property, and not something with side effects. Finally, you can use @synthesize which will automatically create perfect accessor methods for you. No code written by you!

Of course, you should already know that you don’t have to use @synthesize, you can still provide your own implementation, no matter what you wrote in the interface.

Use the dot syntax

This is closely related to the above. Whenever you access something, use myObject.property = ... or ... = myObject.property instead of [myObject setProperty:...] or ... = [myObject property].

The importance is not so much the difference in code length as it is compile-time checking. Objective-C defers as many things to runtime as possible, which is great and all, but it means that you’ll have to use the debugger to find errors that in a different language, the compiler would catch and flag. Sending a message that might not be supported is a warning only, while setting a wrong property is an error which will stop you right dead in your tracks, as it should.

The other important thing is intent. If you are familiar with Objective C patterns, you can decode standard accessor calls while reading code efficiently. But with the dot syntax, you don’t have to do that. Making code more readable is always a good idea, especially if there are no drawbacks.

As always, there are limitations. Don’t try it with ids, for example: [[myDictionary objectForKey:@"key"] stringValue] should stay that way. You can get that to accept the dot syntax with a cast, but that’s just plain ugly and less clear on your intentions.

A tip for true pros: There are quite a few methods where the getter has an “is” in front, like setFlipped: and isFlipped. The compiler won’t allow you to use the dot syntax for these. You can, however, convince it to do so by declaring a category (just the interface, no implementation) like this:

@interface NSImage (PropertyAdditions)
@property (assign,getter=isFlipped) BOOL flipped;
@end

That way, the compiler will allow things like myImage.flipped = YES. It’s a cumbersome hack, true, but I think the strict type-checking outweighs this.

Use for-each enumeration

Another great thing in 10.5 is the for-each pattern. Instead of things like

for (NSUInteger i = 0; i < [array count]; i++)
{
    id object = [array objectAtIndex:i];
    [...]
}

or the horrible, but officially recommended

NSEnumerator *enumerator = [array objectEnumerator];
id object;
while (object = [enumerator nextObject])
{
    [...]
}

writing

for (id object in array)
{
    [...]
}

is less code and again, easier to understand. It’s not applicable in all situations, mainly not when iterating over two arrays in parallel, but when you can, be sure to use it.

Private methods go in class extensions

Mr Shipley recommends to put private methods in a category, to keep things more clean. I think it is more useful to put them in class extensions. Instead of

@interface MyClass (Private)
- (void)_doSomethingSecret;
@end

@implementation MyClass
[...]
@end

@implementation MyClass (Private)
- (void)_doSomethingSecret;
{
    [...]
}
@end

I prefer to have

@interface MyClass ()
- (void)_doSomethingSecret;
@end

@implementation MyClass
[...]
- (void)_doSomethingSecret;
{
    [...]
}
@end

The advantage to using this pattern is that you can group private methods with the methods that use them, which is pretty useful for understanding how code works (and sooner or later, you will have to do research to find out how your code works).

You have to understand: The idea behind putting private methods in a category is to keep them out of the header, where they clearly don’t belong, but still have them declared somewhere so that the compiler won’t say “might not respond to selector…”. The idea of putting them all in a category implementation then is to make sure that the compiler gets annoyed if you forget to implement one of them. Class extensions already provide these two services for you out of the box.

Know manual memory management but use the garbage collector

Starting with 10.5, you can forget about memory management, because a garbage collector is provided. Other implementations of the Cocoa API, like [GNUstep][gnustep], have had this for far longer, but they don’t actually matter. My recommendation: Use it! Nothing is more fun than writing code without having to keep in mind to release this one thing…

On the other hand, this applies only to Cocoa. It does not fully apply to Core Foundation, where you still have to use manual memory management. Anything that is derived from this uses an identical system to that used by old Cocoa. Make sure you know this well, because memory management done wrong is going to bite you.

Never ignore warnings

The default warning level in Xcode is not very high, which is a shame. Instead, follow what [Keith Baur aka OneSadCookie says in his blog][osc]. -Werror (which turns all warnings into errors) is extremely important: If your code gives you a warning, you have a problem. This may not always be a true problem, but it always does mean your code is incorrect. If you have a really good reason for doing what you are doing, there is always a way to tell the compiler about this (in 90% of the cases it’s a simple cast).

Define categories with helper methods

There are many ways where you replicate the same code over and over again. I’d recommend to put this in categories, even if it’s not much. As an example, this one guy I know uses a lot of NSXMLElement, and he has thousands of lines that go [element addAttribute:[NSXMLNode attributeWithName:@"attribute" stringValue:@"value"]];. I’d instead declare

@interface NSXMLElement (Additions)
- (void)addAttributeWithName:(NSString *)name stringValue:(NSString *)value;
@end

@implementation NSXMLElement (Additions)
- (void)addAttributeWithName:(NSString *)name stringValue:(NSString *)value;
{
    [self addAttribute:[NSXMLNode attributeWithName:name stringValue:value]];
}
@end

Then, I can just say [element addAttributeWithName:@"attribute" stringValue:@"value"]. That looks like not much of a gain, but it makes it clearer what your plan is and hides the boring detail. You never care about the NSXMLNode that is the attribute again anyway, so there’s no need to bother with that.

A particular trick I always use when dealing with NSScanner is the scanUpToAndPastString:. Okay, actually it’s a new invention, I used to call it scanPastString: before, but the new name is better at telling what it has to.

@interface NSScanner (Additions)
- (BOOL)scanUpToAndPastString:(NSString *)string;
@end

@implementation NSXMLElement (Additions)
- (BOOL)scanUpToAndPastString:(NSString *)string;
{
    if (![self scanUpToString:string intoString:NULL]) return NO;
    return [self scanString:string intoString:NULL];
}
@end

Not much, but makes my life a whole lot easier. Of course, I could also make it so that it returns the scanned string, like scanUpToString:intoString: does. Or I could implement scanUpToAndPastCharactersFromCharset:. But I don’t need either, so I won’t.

Conclusion

Yeah, that’s pretty much it. I’ll post more if there’s interest and/or I can think of something interesting.

Written on August 5th, 2008 at 07:57 pm

0 Comments

    New comments can no longer be posted because it got to annoying to fight all the spam.