objective-ciphone

Not using header files in Objective-C


I'm creating a small program which consists of a few source files on my desktop (I'm not using Xcode) which I compile from the command line. Since everything is so tiny and small I would like to skip using header files and have everything in my .m file. It would like something like this:

Foo.m

#import <Foundation/Foundation.h>

@interface FooClass : NSObject {
}
- (void) fooFunction;

@end


@implementation FooClass

- (void) fooFunction {

     NSLog(@"Printing bar");

}

@end




Main.m

#include <stdlib.h>
#import "FooFunction.m"


int main (int argc, const char *argv[])
{   

    NSAutoreleasePool * pool = [[NSAutoreleasePool alloc] init];
    NSLog (@"Running....");

    FooFunction *foo = [[FooFunction alloc] init];
    [foo fooFunction];

    [pool drain];
    return 0;

}

When I try to compile this I get ld duplicate symbol fooFunction blahblahblah for architecture x86_64

Any ideas of what I'm doing wrong here?


Solution

  • It's a bad idea to include implementation files like .m files (or .c/.cpp). If you need to include a file, it should probably be .h.

    By including Foo.m, you have two implementations of FooClass existing, which the linker doesn't like. This is because an include is like a copy and paste of the file at that point.

    In your example, the compiler compiles two files - main.m and Foo.m, and in both there is an @implementation section for FooClass.

    You should have one implementation between all compiled files, but you can declare the interface any number of times, which is the reason we put the interface declaration in the header files.

    By this logic, although it isn't the convention, technically you could put everything in a single main.m file and just compile that. However for sanity's sake, once you have more code, you should break it up into class .h/.m files.

    There is one other (bad)option for not using headers, where you add only the @interface section to the files that would include it, but again, I don't recommend this, because you will go through linker hell when you edit one of these copies and forget the other. In your case, you just add the FooClass @interface section to the top of the main.m file.