I often write small tests programs in Objective-C, to experiment stuff or play with something. Most of the time, I put everything in the main.m file, and get rid of everything else:

#!/usr/bin/env objc-run
@import Foundation;

@implementation Hello : NSObject
- (void) sayHelloTo:name
    printf("Hello %s, my address is %p\n", [name UTF8String], self);

int main ()
    id hello = [Hello new];
    [hello sayHelloTo:@"sunshine"];
  • Everything goes into main.m. Or “Test.m”, or whatever. The main() function can be in any file, you know.

  • sha-bang objc-run. If you’re not using it yet, objc-run is Ilja A. Iwas’ excellent utility that “makes it easy to use Objective-C files for shell script-like tasks”. Install it with brew install objc-run and chmod u+x your source file, you’re ready to go.

  • Modules, no precompiled headers. Maybe there are legitimate reasons to keep using #imports and PCH in large projects, but for quick test programs? No way.

  • No @interface declaration. I inadvertently found out the other day that ObjC let you specify the superclass in the @implementation directive; I’m not sure why this is allowed, and of course you can’t change your mind between the @interface and the @implementation. However, you can omit the @interface block entirely.1

  • Implicit parameter types. ObjC methods return types and parameters are implicitely (id), which means -(id)doSomethingWith:(id)param; is exactly the same thing as
    -doSomethingWith:param; which I also find clearer.

  • No arguments to main(). Although it’s considered bad practice, it’s actually legal to write void main () instead of int main (int argc, char**argv). Why bother if you’re not using the arguments?

  • No return from main(). Strangely, -Wreturn-type doesn’t fire a warning when omitting the return from main(). Anyway, this was pointless as I would return zero2. [Update 2014-09-19: Graham Lee tells me that “Since C99, if you return control from main() without a return statement then “return 0;” is assumed.” Cool.]

  • printf, not NSLog. NSLog is for logging errors, not for text output: I don’t need, and I don’t want to printout the executable path and thread ID with each line.

I’m not sure the Radar team will appreciate this kind of “Sample Project” over full-fledged Xcode templates, but I’ll certainly try it out for the next bugreports.

  1. Clang fires a warning, and you can’t mute that one. In the llvm source, that’s the warn_undef_interface warning, and it’s on the list of warnings that have no associated -W flag. Bummer. 

  2. On the other hand, declaring int void main() would fire a 'main' must return 'int' error.