views:

1981

answers:

4

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?

+3  A: 

Declaring the methods in the header file will only stop compiler warnings. Objective-C is a dynamic language, so you can call a method (send a message) to a an object whether or not that method is declared externally.

Also, if you define a method in the .m file above any code that calls it (lazy declaration) then that won't generate any warnings. However the same thing applies, you can send a message to an object without it being declared.

Of course - this means that there are no private methods in Objective-C. Any method that a class implements can be called.

Personal preference. If it's a public method (i.e one used externally). declare it in the .h and define in the .m. If you want to limit it's visibility, or at least indicate that it is a private method, use categories/class extensions in the .m file. Although lots of example code uses the lazy declaration method.

Abizern
+3  A: 

Objective-C treats functions as "messages" and as such, you can send a "message" to any object - even one that doesn't explicitly state in its interface that it can accept. As a result, there are no such things as private members in Obj-C.

This can be very powerful, but is a source of confusion for new Obj-C programmers - especially those coming from C++, Java or C#. Here are the basic rules of thumb:

  • You should define all public methods in your @interface so that consumers know what messages you expect to handle.
  • You should define @private methods in your @interface to avoid compiler messages and avoid having to order the methods in your @implementation.
  • You should use protocols when implementing a particular convention of methods for your class.

Much of this is personal preference, however it helps to avoid annoying compiler warnings and keeps your code organized. and easy to understand.

LBushkin
Clarification: The "@private" keyword can only be used for variable declarations, not methods. Methods intended to be private can be declared in an additional header file which includes the public header and is included by the implementation (instead of the public header).
Quinn Taylor
+15  A: 

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. :-)

Quinn Taylor
+1. Thanks for raising that we shouldn't need steel plates to keep coworkers from messing with our cubes and we shouldn't need language enforcement to keep them from messing with internal data structures. If we need either, we need better coworkers. Compiler warnings are important (along with -Werror), just like little labels on food in the fridge saying "this is mine, don't eat it." ObjC is a language for grown-ups. You follow the rules even when your mom (the compiler) isn't forcing you. And so you don't have to find tricks around the compiler like you do so often in other languages.
Rob Napier
+1 Great answer! :)
Perspx
I hope I'm not missing the point, but I have often wondered if it is possible to hide member variables using this structure of layered API's, or does everything still need to be declared in MyClass.h?
Akusete
A: 

As Quinn said, i tried to put a method prototype in the @implementation section of the .m file to not get compiler warning when two method have cyclic references/calls to each other. But when I do this I get a compiler error; more specifically a syntax error. The syntax for the prototype is the same as if a would put it in the @interface section, right?

Thanks, Mac

Mac4711
Mac4711, you've provided an answer to my question on objective-c methods, which in turn is a question. You really need to start a brand-new stack overflow question -- feel free to link to this one if it helps. Users can only add comments to answers; there is no good mechanism to add answers to an answer, and, users do not look through answers to other questions to find questions to answer [or, in other words, (almost) no one will see your question, and they can't really answer if they did.]
Clinton Blackmore