When do I define objective-c methods?

Clinton Blackmore picture Clinton Blackmore · Jun 19, 2009 · Viewed 14.4k times · Source

I'm learning Objective-C, and have a C/C++ background.

  • In object-oriented C++, you always need to declare your method before you define (implement) it, even if it is declared in the parent class.

  • In procedural-style C, IIRC, you can get away with just defining a function so long as it is only called from something else in the same compilational unit (ie. the same file) that came later on in the file (well, provided you don't declare it elsewhere with "extern").

  • Now, in Objective-C, it appears that you only need to declare selectors in the header file if they are going to be used by something external, and that you can make up selectors in your .m file just fine, and call them within the .m file. Also, it appears that delegate methods or inherited methods are never (re)defined.

Am I on the right track? When do you need to define a selector in Objective-C?

Answer

Quinn Taylor picture Quinn Taylor · Jun 20, 2009

For Objective-C methods, the general practice is to put methods you wish to expose in the @interface section of the header file so other code can include only the .h and know how to interact with your code. Order-based "lazy declaration" works just like functions in C — you don't have to declare a method prototype unless you have a dependency that can't be resolved by ordering, but you can add method prototypes inside the @implementation if needed.

So yes, you're on the right track. Don't repeat the method prototype for inherited methods — the compiler finds it in the parent's header file. Delegate methods may be defined as prototypes in a category (tacked onto a class) and implemented as desired, but the delegate does not need to provide a method prototype, since it is already defined. (It still can if it wants to for clarity, etc.)

Since you're just learning Objective-C, the rest of this answer is much more detail than you asked for. You have been warned. ;-)


When you statically type a variable (e.g. MyClass* instead of id) the compiler will warn you when you try to call a method that a class doesn't advertise that it implements, whether it does or not. If you dynamically type the variable, the compiler won't stop you from calling whatever you like, and you'll only get runtime errors if you call something that doesn't exist. As far as the language is concerned, you can call any method that a class implements without errors at runtime — there is no way to restrict who can call a method.

Personally, I think this is actually a good thing. We get so used to encapsulation and protecting our code from other code that we sometimes treat the caller as a devious miscreant rather than a trustworthy coworker or customer. I find it's quite pleasant to code with a mindset of "you do your job and I do mine" where everyone respects boundaries and takes care of their own thing. You might say that the "attitude" of Objective-C is one of community trust, rather than of strict enforcement. For example, I'm happy to help anyone who comes to my desk, but would get really annoyed if someone messed with my stuff or moved things around without asking. Well-designed code doesn't have to be paranoid or sociopathic, it just has to work well together. :-)

That said, there are many approaches for structuring your interfaces, depending on the level of granularity you want/need in exposing interfaces to users. Any methods you declare in the public header are essentially fair game for anyone to use. Hiding method declarations is a bit like locking your car or house — it probably won't keep everyone out, but (1) it "keeps honest people honest" by not tempting them with something they shouldn't be messing with, and (2) anyone who does get in will certainly know they weren't supposed to, and can't really complain of negative consequences.

Below are some conventions I use for file naming, and what goes in each file — starting from a .m file at the bottom, each file includes the one above it. (Using a strict chain of includes will prevent things like duplicate symbol warnings.) Some of these levels only apply to larger reusable components, such as Cocoa frameworks. Adapt them according to your needs, and use whatever names suit you.

  • MyClass.h — Public API (Application Programming Interface)
  • MyClass_Private.h — Company-internal SPI (System Programming Interface)
  • MyClass_Internal.h — Project-internal IPI (Internal Programming Interface)
  • MyClass.m — Implementation, generally of all API/SPI/IPI declarations
  • MyClass_Foo.m — Additional implementation, such as for categories

API is for everyone to use, and is publicly supported (usually in Foo.framework/Headers). SPI exposes additional functionality for internal clients of your code, but with the understanding that support may be limited and the interface is subject to change (usually in Foo.framework/PrivateHeaders). IPI consists of implementation-specific details that should never be used outside the project itself, and these headers are not included in the framework at all. Anyone who chooses to use SPI and IPI calls does so at their own risk, and usually to their detriment when changes break their code. :-)