I'm still fairly new to Objective-C but I'd love to learn more about how it should be done.
I'm building a simple cheat sheet that I'd like to print and put on my office wall as a reminder.
Here's what I have so far:
// Headers (.h)
// Shows what's available to other classes
#interface ExampleViewController : UIViewController
// Declare public methods, ivars &
// properties that are synthesized.
#end
// Implementation (.m)
// Defines the content of the class
#interface ExampleViewController ()
// Class extension allowing to declare
// private methods, ivars & properties that are synthesized.
#end
#implementation ExampleViewController
// Private Properties
// Method definitions
#end
One thing I don't understand is why have both #interface and #implementation inside the implementation .m file?
I get that we can declare private stuff but why not simply throw them in #implementation like:
#implementation ExampleViewController
UIView *view; // private property
- (void)...more code
#end
#1 - Why should I ever use #interface from within my implementation .m file?
#2 - For header .h, why should I ever use #class more than #import?
#import actually gets the whole definition and #class tells the compiler that the symbol is a class. So I just don't see why I should ever use #class?
#3 - Otherwise, is there anything I should be adding somewhere in my .h or .m cheat sheet?
That's not a problem-related question but a more wiki-esque question so we everybody can look it up and completely and quickly understand those concepts as they are very hard to grasp for any newcomer.
Why should I ever use #interface from within my implementation .m file?
Because it's better to clearly separate public and private parts of the class.
For header .h, why should I ever use #class more than #import?
When forward-declaring classes for use in protocols. Like this:
#class Foo;
#protocol FooDelegate
// this wouldn't compile without a forward declaration of `Foo'
- (void)fooDidFinishAction:(Foo *)f;
#end
Otherwise, is there anything I should be adding somewhere in my .h or .m cheat sheet?
That's way too general to be answered in one post.
1 - Why should I ever use #interface from within my implementation .m file?
When you do not intend to expose that interface to any other component. That's certainly the case for private class extensions but may also apply for something like a test which doesn't need a .h file at all because while it does define a class it does not need to expose an interface for any other component to use.
2 - For header .h, why should I ever use #class more than #import?
Invert your question; why should I ever use #import rather than #class?
#class informs the compiler that a class definition of that name will exist to be linked but says nothing about it's interface.
#import makes the class' interface available to you.
A forward declaration requires less work and can allow for faster builds. It is also not always possible to #import a class at all times (as in circular references like #H2CO3's protocol example). If all you need to know is that a class exists then just use the forward declaration. When you actually need to interact with its specific interface (usually in your class' implementation) then you need to #import.
3 - Otherwise, is there anything I should be adding somewhere in my .h or .m cheat sheet?
Unless you intend to actually expose ivars as a public interface (almost certainly not the case) leave them out of your .h and expose only properties instead.
Keep your public interface as simple as possible. Try not to reveal implementation details. However keep it informative enough that users of the class can verify its behavior using that public interface. (I find test driving the design of the class using only it's public interface a good tool for striking this balance.)
Imports and forward declarations expose dependencies. Keep them to the minimum you actually need so that you can understand what the class in question actually depends on.
Delegate protocols and block types are a common part of a class' interface but not part of the #interface. Include them in the .h if they are needed by other classes (e.g. to register callbacks).
Related
May I know what is the difference between instance variable in .h file and property in .m file in objective c?
I know that both cannot be used outside the class. Any other difference?
A. You can add ivars inside the implementation, too:
#implementation AClass
{
id ivar;
}
Therefore the difference is not that ivars has to be in the header (interface). (But see below B.)
B. If an ivar should not be used outside, there is no reason to put it in the public header. Why do you want to inform somebody about an ivar, if he cannot use it? This is source code spamming.
C. A property adds (or uses) an ivar. Additionally it adds accessor methods.
D. A property provides additional semantic information, especially about atomicity and setter semantics, if it is declared in the header.
Up to here it should be clear that properties are usually the better way to model an object state. So why do we have ivars in headers?
This is for legacy. In former times we did not have declared properties. There has been some reasons for having ivars in the header (for example to tell the compiler the object size), but this are gone. The only meaning for declaring ivars in the header in nowadays is that you make them public and let others access them directly for performance reasons. You should have very good performance reasons to do so. I had never had them.
In addition to Jef's answer:
If you want to make ivars public to subclasses, you can put them into a class continuation in an extra file. Let's have an example:
MyClass.h
// We do not put ivars in the public header. This is an implementation detail.
#interface MyClass : NSObject
…
#end
MyClass_SubclassAddition
// We do put ivars in an extra header with a class continuation, to make them visible for subclasses
#interface MyClass()
{
id ivar;
}
#end
MyClass.m or MySubclass.m
// We use both headers in the implementation and subclass implementation:
#import "MyClass.h"
#import "MyClass_SubclassAddition.h
#implementation MyClass
…
#end
You can get rid of the "subclass ivar problem", if you use setters in initializers. Whether this is wrong or not to do so, is a different discussion. Personally I prefer to use setters. But do not let us start that discussion again (and again and again …)
the biggest practical difference is that subclasses can see and use ivars which are declared in the .h, where if they are in an extension at top of the implementation file a subclass cannot access them.
I like to start with them in the .m file but i'll happily move one to the header in order to use it from a subclass.
I came from front-end development, so MVC and OOP still give me some head shakes. Just to explain to you I send like 500 dicionaries (with 100 parameters) to a nodejs server. The problem is that I has creating ivars for each parameter and each dicionary. Now I want to create some classes like a person class, in the same header file that I have my syncronization class for example. I can make something like this on the header:
#import <Foundation/Foundation.h>
#import "GCDAsyncSocket.h"
#class GCDAsyncSocket;
#interface socketDelegate : NSObject<NSStreamDelegate>
{
NSInputStream *inputStream;
NSOutputStream *outputStream;
NSMutableArray *messages;
GCDAsyncSocket *socket;
dispatch_queue_t connectionQueue_;
}
- (void) initNetworkCommunication;
- (void) sendMessage:(NSArray *)message:(int)numberOfContactsToSend;
#end
#interface personInfo: NSObject
#property (nonatomic,weak)NSString*firstName;
#property (nonatomic,weak)NSString*lastName;
#property (nonatomic,weak)NSDictionary*dicToSendWithConctactInfo;
#end
But in the implementation I don't know how to handle the multiple classes. Like I've a method inside the "socketDelegate" class that needs to use the person class, but it's not available inside it.
What's the best way to implement this?
To answer your immediate question, you can just forward-declare personInfo at the top of the file before socketDelegate:
#class personInfo;
Usually you just put each public class in its own implementation and header files, and each implementation file includes the header files of all the classes it uses. The header files usually just need to forward declare the classes they refer to (as you are doing with #class GCDAsyncSocket;. However, it doesn't make sense that you are both importing #import "GCDAsyncSocket.h" and forward-declaring. From what you are using it for here, you don't need the import. However, to properly use GCDAsyncSocket, you will need to implement GCDAsyncSocketDelegate protocol, which will require you to import the header; however, you should probably implement that protocol as part of a "class extension" inside the implementation file).
You only need to import the header of something in your header if you are subclassing a class, or implementing a protocol that is declared in the header. For all other uses (i.e. using the class or protocol as part of a pointer type), you can simply forward-declare it. (And for implementing a protocol, you can do that in the implementation file with a "class extension" if you don't need people to know you're implementing the protocol.
Different classes should, typically, be in different files. Once PersonInfo (please capitalize class names) has it's own PersonInfo.h and PersonInfo.m, then you simply add
#import "PersonInfo.h"
to the header file above to be able to reference PersonInfo from your SocketDelegate class (again, please capitalize class names).
I am wondering why there is twice #interface. One in class.h and other in class.m. For example:
TestTableViewController.h:
#import <UIKit/UIKit.h>
#interface TestTableViewController : UITableViewController
#end
and (automatically generated) class.m i find:
#import "TestTableViewController.h"
#interface TestTableViewController ()
#end
#implementation TestTableViewController
... methods delegated from UITable delegates
#end
So my question is, what the #interface TestTableViewController () in the .m file is about. Why it is there? Do I need it?
Thanks in advance
The second #interface directive is in the implementation file (.m) -- you can infer from it that it's meant for declaring stuff that the creator of the class didn't want to expose to the user of the class. This usually means private and/or internal methods and properties. Also note that there are two types of doing this. The one (which you see here) is called a "class extension" and it's denoted by an empty pair of parentheses:
#interface MyClass ()
This one is particularily important because you can use this to add additional instance variables to your class.
The second one, called a "category", is indicated by a non-empty pair of parentheses, enclosing the name of the category, like this:
#interface MyClass (CategoryName)
and it's also used to extend the class. You can't add instance variables to a class using categories, but you can have multiple categories for the same class, that's the reason why it's mainly used to extend system/framework classes for which you don't have the source code -- so a category, in this sense, is the exact opposite of the class extension.
The second "interface" defines an extension for the "TestTableViewController" class, which is not visible to someone who only imports the h file. This is the de-facto way for creating private methods in objective C.
In there you can declare private methods and properties that you only want to use in your class, but not expose to other classes.
The interface in the TestTableViewController.h file is the declaration of a class extension. There are 2 round brackets that show this. The syntax is the same as for writing a category for a class. But in this case it's used to declare some sort of private methods the author does not want to expose in the header file
A normal category interface looks like this:
#interface TestTableViewController (Your_Category_Name)
- (void)doSomething;
#end
And the corresponding implementation:
#implementation TestTableViewController (Your_Category_Name)
-(void)doSomething {
// Does something...
}
#end
In your example there is no category name specified, so it just extends the class and you can implement the method in the normal implementation.
Normally this technique is used to "hide" methods. They are not declared in the header file and are not visible if you only import the .h file.
I am watching the Stanford University iPad and iPhone application Developments course video. The instructor says in the video we can control-drag an UI object to the implementation files to create an action. But in this way the method will not declare in the header file. Does this mean it is ok to implement methods in the .m file but not declare in the .h file?
Depends on how you define "ok" :-)
Objective-C uses dynamic method lookup and does not really enforce access ("private", "public", etc.) specifiers. So you don't need to declare any method in a header file.
However you will end up fighting the compiler as it does do a fair amount of type-checking unless you persuade it not to, and you'll lose by doing so.
You are not required to declare in the header file all methods in the implementation. But if not in the header file obviously you cannot reference them by literal name in another file, nor can you "forward reference" them in the implementation file.
(Note that this is not that different from regular C, but is different from methods of a class in C++.)
It's "OK" to not declare methods in the header yes, under certain circumstances. For instance, if using ARC then the compiler generally needs to know the method signature so it can do the right thing. But basically all it means is that wherever you're using the method, it must already know about the method you're calling.
Since you're talking about Interface Builder, that's slightly different in that it will know about all methods since it can "see" the whole context of your header and implementation files and know that a method exists. i.e. in my terminology above, the method has been defined before it's used.
With regard to defining before use, the general accepted approach is to either:
Define a method in the interface file (.h). e.g.:
MyClass.h
#interface MyClass : NSObject
- (void)someMethod;
#end
MyClass.m
#implementation MyClass
- (void)someMethod {
// do something
}
#end
Define a method in a class continuation category. e.g.:
MyClass.h
#interface MyClass : NSObject
#end
MyClass.m
#interface MyClass ()
- (void)someMethod;
#end
#implementation MyClass
- (void)someMethod {
// do something
}
#end
Is there any difference in doing
#class MyViewController;
rather than doing the normal import of the .h into the appdelegate.h
#import "MyViewController.h"
I've seen some example recently that use the #class way and wondered if there any differences.
thanks.
There is a big difference.
#class MyViewController;
Is a forward declaration for the object MyViewController. It is used when you just need to tell the compiler about an object type but have no need to include the header file.
If however you need to create an object of this type and invoke methods on it, you will need to:
#import "MyViewController.h"
But normally this is done in the .m file.
An additional use of forward declarations is when you define a #protocol in the same header file as an object that uses it.
#protocol MyProtocolDelegate; //forward declaration
#interface MyObject {
id<MyProtocolDelegate> delegate;
...
}
...
#end
#protocol MyProtocolDelegate
... //protocol definition
#end
In the above example the compiler needs to know that the #protocol MyProtocolDelegate is valid before it can compile the MyObject object.
Simply moving the protocol definition above MyObject definition would also work.
#class allows you to declare that a symbol is an Objective-c class name without the need to #import the header file that defines the class.
You would use this where you only need the class name defined for the purposes of declaring a pointer to the class or a method parameter of the class, and you do not need to access any methods, fields, or properties in the class.
It saves a minuscule amount of compile time vs the #import, and it sometimes helps avoid messy include circularity issues.
[And, as rjstelling points out, it's sometimes useful where you have interleaved declarations and you need to "forward declare" something.]