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 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, 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. -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 09:57 pm

2 Comments

  1. Posted 6 August 2008

    Joachim

    Hm, ich muss sagen, ich habe nicht ganz verstanden in welchem Fall der Compiler mit .-Schreibweise nen Fehler anzeigt, mit der [objekt setBla] bzw. [objekt bla] Methode jedoch nicht.
    Ich habe eine Idee, bin mir aber nicht sicher, ob das so ist bzw. ob du das meintest: Meckert Xcode nicht, wenn ein Objekt eine bestimmte Methode nicht bereitstellt? Dann würde ich verstehen, dass man sich beim Methodenaufruf leicht vertippt und das nicht merkt, was aber bei der Punktschreibweise angemeckert wird... Aber normalerweise bekommt man da doch eine Warnung à la "bla may not respond to blub".

    Allgemein zur Punkt-Schreibweise: Da gibt es glaube ich sehr geteilte Meinungen drüber. ^^ Aaron Hillegass schreibt zum Beispiel in seinem aktuellen Buch "Cocoa programming for Mac OS X":
    "Overall, I think that is a rather silly addition to the language since we already had a syntax for sending messages."
    Ich habe auch letztens irgendwo die Meinung gelesen, diese Schreibweise passe nicht zum Stil von Objective-C.
    Diese Argumentation kann ich durchaus nachvollziehen, da die Idee hinter Objective-C doch ist, so ziemlich alles als normal "als Satz" lesen zu können. Das ist mit Punkt-Schreibweise denke ich nicht so gut möglich.
    Für alle die von Java oder ähnlichen Programmiersprachen kommen ist das sicherlich einfacher zu verstehen und sie müssen nicht soviel umlernen.

    Zu den Warnungen: Da würde ich zustimmen... Kann man das "Warnungs-Niveau" in Xcode denn entsprechend hoch-/umstellen? Bei Eclipse habe ich mal gezeigt bekommen, was man da alles als Warnung angezeigt bekommen kann (zum Beispiel wenn man keinen javadoc-Kommentar an einer public-Methode hat), was ich sehr praktisch fand und wodurch ich meiner Meinung nach einige Dinge ordentlicher mache (obwohl und weil man dauernd getriezt wird). Solche Einstellungen fände ich bei Xcode auch sehr interessant...

  2. Posted 6 August 2008

    Torsten (admin)

    Generell erlaubt der Compiler die Punkt-Syntax, wenn er die Klassendefinition gesehen hat und es dort entweder eine mit @property definierte Eigenschaft gibt, oder eine setValue mit passender value Methode gibt. Das geht natürlich nur, wenn der Typ einer Variable bekannt ist, sie also nicht id ist.

    Stimmt, der Compiler gibt sonst auch eine Warnung aus, mir gefällt ein echter Fehler einfach besser. Zum Stil: Das ist letztendlich jedem selbst überlassen. Ja, auf den ersten Blick passt die Syntax nicht zu Objective-C. Allerdings ist es letztlich fast genau die selbe Syntax, die auch bei Key-Value-Coding überall verwendet wird, also ist es auch nicht so sehr anders. Und natürlich verwendet Standard C die selbe Syntax um auf Structs zuzugreifen. Der Vorteil, den ich hier sehe, ist, dass es erstens eindeutiger ist (Ich will hier letztlich nicht wirklich eine Message senden und etwas aktiv tun, sondernd nur einen Wert setzen und auslesen), und zweitens, dass ich das ganze als lvalue, also auf der linken Seite eines Zuweisungsoperators, verwenden kann. Die Eigenschaften von structs setze ich ja genauso, daher halte ich dies für eindeutiger. Insgesamt halte ich das für eine Geschmacksfrage. Da dies meine Homepage ist, ist es mein Geschmack der hier erwähnt wird ^^.

    Warnungen: Kann man leider nicht allgemein für Xcode festsetzen, dass muss man für jedes Projekt neu machen. Dazu in Xcode das Informationen-Fenster der Projektdatei aufrufen (Befehl-i). Dort gibt es dann das Feld "Build", und darunter den Bereich "GCC 4.0 Warnings". Leider gibt es für viele schöne Sachen dort keine Checkbox, daher nehme ich einfach die Warnungen von dem Link und schreibe die unter "Other Warning Flags".

Write your own