I try to import as very little as possible in my header files (using the implementation file instead), and for classes we can use #class, but what about protocols? If I try to declare a protocol that I'll be using in that header with #protocol I get a warning that "Cannot find protocol definition for '...'"
Is the proper way to handle this simply by importing the header that does the protocol declaration? (so one .h file imports the other .h)
Example for ListViewController.h:
#import <UIKit/UIKit.h>
#import "JTRevealSidebarV2Delegate.h" // is this the best way?
#class List;
#protocol JTRevealSidebarV2Delegate; // this produces a warning.
#interface ListViewController : UIViewController <UITableViewDataSource, UITableViewDelegate, JTRevealSidebarV2Delegate>
You need the #import. #protocol doesn't give the compiler enough information to do its type checking.
(When you declare a property of type List all it needs to know is that you really mean List and not, say, Lisp. A pointer to any object is the same size. A protocol, on the other hand, contains a list of stuff that a class needs to do. It needs to know what "stuff" is to do anything useful.)
It's correct, but if you want to get picky you can always create a single .h file where you declare your protocol only, and have both your ListViewController and JTRevealSidebarV2Delegate import it
Steps to do
make a protocol.h file declare your #optional methods etc
in your class A import protocol.h and implement the methods.
Use reference of the calss A's obj to call its methods of protocol from any place.
Related
Forward declarations are used to reduce dependencies and prevent unnecessary imports where multiple header files are involved.
This being said, how should I go about this scenario?
Let's say I have the following:
ClassAlpha.h
#interface ClassAlpha: NSObject
-(void)helloWorld;
#end
ProtocolA.h
#protocol ProtocolA <NSObject>
-(void)doSomethingWithAlpha:(ClassAlpha *__Nonnull)alpha;
#end
ClassBeta.h (conforms to ProtocolA)
#interface ClassBeta: NSObject<ProtocolA>
#end
ClassBeta.m
#import "ClassAlpha.h"
#implementation ClassBeta
-(void)doSomethingWithAlpha:(ClassAlpha *)alpha
{
NSLog(#"Hello");
}
#end
In ProtocolA.h, should I use a forward declaration of ClassAlpha? However, if I were to do so, that would mean that ClassBeta would have to be the one that imports ClassAlpha within its implementation, alongside importing ProtocolA. Alternatively, if I were to use the import statement of ClassAlpha within ProtocolA, needless to say ClassBeta woudldn't need to do so. What would be the best practice for this situation?
You should avoid #import in headers as much as possible. So, yes, you should use a forward declaration of ClassAlpha (i.e. #class ClassAlpha;) in PrototolA.h, because to use ClassAlpha * as a type in a parameter declaration, all you need to know is that ClassAlpha is the name of a class. You don't need to know anything else about how it is declared. Yes, you should import ClassAlpha.h in ClassBeta.m; you should do imports in implementation files as much as possible instead of header files.
Im trying to implement Pushwoosh into my game its very simple guide but I'm running into this issue here:
Your AppDelegate implementation should look like this:
#implementation AppDelegate <PushNotificationDelegate>
in line 20.
This means that your AppDelegate conforms to PushNotificationDelegate protocol.
Read up on protocols. Basically, a protocol is a list of methods and/or properties that an object must (or may, in the case of #optional properties) have. You read NSObject<PushNotificationDelegate> in that error message as "any NSObject subclass that declares that it implements the methods in the PushNotificationDelegate protocol".
To declare your class conforms to a protocol, you write the name of the protocol(s) in between < and > at the end of one of its #interface or #implementation lines.
The compiler reads each source file separately, and all the headers you #import from that source file (read up on "compilation units" if you want to learn more). So if you write the <PushNotificationDelegate> bit in the .m file, only code in the .m file knows about it, because other .m files only see what you wrote in the header.
In your case, the AppDelegate.m source file should see that, but maybe you have another source file in which you set the same type of delegate that only includes the header for AppDelegate and thus can't see it?
Anyway, if you read this error message with this knowledge, you'll see that PushNotificationManager.delegate is declared as NSObject<PushNotificationDelegate>, and that's what your AppDelegate has to be to be able to assign it to that property. And the error correctly says that an AppDelegate may be an NSObject, but not a PushNotificationDelegate.
The advantage of declaring that your class conforms to a protocol is that the compiler will print an error message if you forget to implement a required method.
For my case, I need to conform the protocol in the header file to silent the warning. I don't know what I'm doing.
#import <UIKit/UIKit.h>
#import "BaseAppDelegate.h"
#import <Pushwoosh/PushNotificationManager.h>
#interface ChildAppDelegate : BaseAppDelegate <UIApplicationDelegate, PushNotificationDelegate>
#end
I have been following the rule of having:
#MyClassName in the header file of a class
&&
#import "MyClassName" in the implementation
I have now decided to subclass one of my view controllers. If I overwrite a method then I get the following message:
Receiver 'MyClassName' for class message is a forward declaration
To over come this I need to put the #import into the header file which doesn't seem to follow what I thought was best practices.
Can someone explain if I have misunderstood the use of #class?
Or if I am dong things correctly, can someone please explain you need to break best practices and use #import in header file when subclassing?
Many thanks.
Edit:
Thanks for the answers. I think I need to add some more detail to clarify my situation and hopefully my understanding. Here is my header for my base class:
#import <UIKit/UIKit.h>
#import "CorePlot-CocoaTouch.h"
#class Organisation;
#interface LongCallDetailViewController : UIViewController <UITableViewDelegate, UITableViewDataSource>
In my impementation I have
#import "Organisation.h"
My subclass header contains the following:
#import "LongCallDetailViewController.h"
#interface LongCallSubclassViewController : LongCallDetailViewController
#end
If I override a method in the subclass and try to use an Organisation object it gives me the error as I stated above. Therefore I either need to add #import "Organisation.h" into the base classes header or duplicate the #import "Organisation.h" into the subclasses implementation file. Both of which seem wrong to me.
Many thanks.
Within header files, you should be importing other header files for any classes you subclass. You do not need to import header files for classes that are just referenced and not subclassed. For example, a header file might look like:
#import "MySuperClass.h"
#class MyObjectType;
#interface MySubClass : MySuperClass
#property (strong) MyObjectType *value;
#end
Edit:
Based on your new edits, it looks like you are writing your header files correctly. When you only declare #class in a scope, you will not be able to access any of the selectors or properties associated with that class. It is okay to declare using #class in places where you are not intending to use selectors or properties of that class type and just pass around a reference (as in the header I have described above), but as soon as you want to do anything else with the object, you'll need to have imported the header file describing the #interface.
When defining a #class MyObjectType in a header file, it is generally expected that the #import "MyObjectType.h" appears in the associated source file. Header files are intended as a declaration of structure, whereas source files will contain the implementation. For example, the source file associated with the header file I described above might look like:
#import "MySubClass.h"
#import "MyObjectType.h"
#implementation MySubClass
- (void)overriddenFunction {
[self.value anObjectTypeSelector];
}
#end
You shouldn't think about "duplicating" an import statement when they're in two different scopes. When you forward declare #class Organisation in your LongCallDetailViewController header file, you'll have a #import "Organisation.h" in your LongCallDetailViewController source file. If you also need to access this object's properties and selectors in your LongCallSubclassViewController class, you'll need to #import "Organisation.h" in your LongCallSubclassViewController implementation file. Remember: the implementation files do not know about the content of each other; they only know about the contents of the header file.
#import imports definition of class with all public methods and properties.
#import predeclare class, so there is no information about methods and properties
You use #import when:
You subclass a class - other classes importing your class need to know about all methods that class suport.
You implement a protocol - same reason as above.
Which one is the best practice-
I have 10 different types of protocol, which is conformed by 10 different class object (),
classA conform to protocolA
classB conform to protocolB
...
...
You may consider them one-to-one relation rather than shared protocol by 2 different class.
Now should i group all these 10 protocols in a header file named Protocol.h and then import that header file when any class want to conform his protocol. Like in class A -
#import Protocol.h
Or should i place each protocol in the header file of the class which contain object that conform particular protocol,like- object_name<protocol> . Like Class X contain object of ClassA which conform to ProtocolA.
#protocol ProtocolaA <NSObject>
#interface ClassX:
{
id <ProtocolA> objectA;
}
Thanks for your reply.
There's no right or wrong answer to this. My personal preference is generally one protocol per header. However, if there are two or more protocols that go logically go together and will usually be imported together, you might put them in the same header file.
If your protocols form an API for a framework, that is another reason to put them together so classes that use the framework API can just do one import.
But I would recommend not using a generic name like protocol.h, try to think up something more descriptive of what the protocols are actually for e.g. all the protocols and class interfaces for Cocoa are logically imported (nested imports are used) in one header called Cocoa.h.
On the second part, I find it generally better to keep protocols and class interfaces in separate headers.
I would not put all protocols in one header, as each protocol is only needed by one class. Importing the protocol header would give you all protocols.
What Apple is doing in these cases is:
1) Include the protocol in the header of the class where the protocol is used (for example UITableView.h and UITextView.h):
#class ClassX;
#protocol ProtocolX<NSObject>
// Use ClassX here
#end
#interface ClassX
#property (nonatomic) id <ProtocolX> myProtocol;
#end
2) Another solution seen in Apple's header is to have an own file for both the header and the implementation (for example CLLocationManager.h and CLLocationManagerDelegate.h).
Bottom line: I would prefer both these solutions to putting all protocols in one header.
You may place protocol in the header file of the class which contain object that conform particular protocol or add protocal as new file.
Working with Protocols
I'm trying to do some animations on an object that I have setup via IB. I'm adding a forward declaration to my .h like so:
#class MySpecialClass;
and then setup a property like so:
#property (nonatomic, retain) IBOutlet MySpecialClass *specialClass;
I want to be able to hide the specialClass using setAlpha, but I get the following error from xcode when trying to compile.
Receiver type 'MySpecialClass' for instance message is a forward declaration.
Do I need to import my class instead of a forward declaration? I'd like to not have to import anything unnecessary if I don't have to.
Forward declaration just tells the compiler, "Hey, I know I'm declaring stuff that you don't recognize, but when I say #MyClass, I promise that I will #import it in the implementation".
You use forward declaration to prevent stuff like circular includes (MyClass imports YourClass which imports MyClass which...), but the 'promise' you make with your code, is that you'll #import it later
You need to import it. Forward declaration is just to silence the compiler that this class exists, but it has no idea about its members, methods, properties, size...