How can you conditionally include protocols during compiliation? - iphone

Is it possible to conditionally include a protocol? For example, below is some code that does not work, but should give you an idea what I'm referring to. I only want the interface AdWhirlDelegate to be included if ads are turned on.
// this works fine
#if ADS_SUPPORTED
#import "AdWhirlView.h"
#endif
// this does NOT work
#interface MyAppDelegate : NSObject <UIApplicationDelegate #if ADS_SUPPORTED ,AdWhirlDelegate #endif>

You could do:
#if ADS_SUPPORTED
#interface MyAppDelegate : NSObject <UIApplicationDelegate,AdWhirlDelegate>
#else
#interface MyAppDelegate : NSObject <UIApplicationDelegate>
#endif
...but then IB can get a little confused. See this answer, which presents an alternative to that.

That won't work
Repeat the interface declaration twice , one with the protocol and one without blocked inside the #if/#else/#endif structure
Preprocessor directives will only work in a non nested way like your header include.

Related

Cannot declare variable inside #interface or #protocol

I have an iOS app built since the beginning with an error in it. Since the source was began constructed from the template, its appdelegate.h looks like:
#interface myAppDelegate : NSObject <UIApplicationDelegate> {
UIWindow *window;
myViewController *viewController;
}
BOOL myBool; // intended to be globally accessible
NSString *myString; // intended to be globally accessible
#end
I refer to myBool and *myString from many other .m source files, as to global variables.
Below XCode 3.2.6, I can not remember getting any issues at compile time.
At 3.2.6, warning appeared at compile pointing to these “global” variables in appdelegate.h, saying: “Cannot declare variable inside #interface or #protocol”. As there were no further problems with compilation or during app runtime, unfortunately I did not consider these warnings.
Now, using XCode 4.2, I am unable to compile this source, because the former warnings turned into build errors. They refer and point to each of those lines in the different .m files where there is a reference to the “global variables”.
Is there an easy way to correct this problem, considering that I still want to access these variables/references as global ones?
Additional question: while I am evaluating so far received answers (thanks for all of you), another question: any idea why no warning were given below XCode v3.2.6, and only warnings in 3.2.6 if this is a real error from my side? And why the code was still compiled and could be run without any problem?
They can't go there. You can put them inside the curly braces {} like this:
#interface myAppDelegate : NSObject <UIApplicationDelegate> {
UIWindow *window;
myViewController *viewController;
BOOL myBool; // intended to be globally accessible
NSString *myString; // intended to be globally accessible
}
#end
And that makes them global to the implementation class. But if you want them global to every class in your app then you should drop them in your App-Prefix.pch file:
//
// Prefix header for all source files of the ... project
//
#import <Availability.h>
BOOL myBool; // intended to be globally accessible
NSString *myString; // intended to be globally accessible
#ifndef __IPHONE_3_0
Are you trying to define them as public members on a class? Classes in Objective-C are rather different than in other languages you might be familiar with. Outside of the curly braces you can only define methods. If you want to make a publicly-accessible member, define them as properties:
#interface myAppDelegate : NSObject <UIApplicationDelegate> {
UIWindow *window;
myViewController *viewController;
BOOL _myBool;
NSString *_myString;
}
#property BOOL myBool; // intended to be globally accessible
#property NSString *myString; // intended to be globally accessible
#end
Then in your #implementation do something like:
#implementation myAppDelegate
#synthesize myBool = _myBool;
#synthesize myString = _myString;
Then you can access them as myObject.myBool and so on.
If you are just trying to make them into static ("global") data for all instances of the class, then as other posters have said, you want to move the definition into your .m file (and ideally declare them static so they won't cause link issues).
The compiler is complaining about the variables being in the #interface block, so move them out of it, either above the #interface or below #end. You'll actually probably want to change them to externs in the header and actually declare them in the .m file.
C Global variables should be declared in .m implementation files, not in .h header files. An extern declaration can go in the .h header files, usually after the includes and outside the interface declarations.
It's also good practice to initialize global object pointers to nil, or else they might contain a garbage object reference.

Headers #import versus #class [duplicate]

This question already has answers here:
Closed 11 years ago.
Possible Duplicate:
#class vs. #import
In the .h file you can add a class to be seen(dont know what the correct terminolgy for this is) by using
#import "SomeClass.h"
or instead use
#class SomeClass;
I've tried both methods and they both worked. Whats the difference? Should I be using one of the methods and not the other? What is best practice?
#import includes the content of the header in the source.
Thus, every declaration which is in the imported header is also imported.
#class only declares to the compiler that the given class exists, but does not import the header itself. It is called a forward declaration, as you only declares to the compiler that the class exists before defining it in details (telling which methods it implements and so on)
Consequences:
When using #import in your .m file, if the header is modified, it will trigger the recompilation of the .m file that #import it on next compilation. Instead, if you use #class, your .m does not depend on the header and if the header is modified, the .m file is not recompiled.
Using #class also avoid cross-imports, e.g. if the class A references class B and class B references class A, then you can't #import "A.h" in B.h and #import B.h in A.h in the same time (it would be an "import infinite loop")
Using #class only declare that a class exists and does not tell the compiler which methods the class responds to.
This is why usually the best practice is to forward-declare the class using #class A in the header (.h) files that references class A, just so that the compiler knows that "A" is a known class but doesn't need to know more, and #import "A.h" in the implementation (.m) file so that you can call methods on the objet of class A in your source file.
In addition to avoid import loops, this will also avoid to recompile files if they don't need to, and thus reduce your compile time.
The only exceptions are when the declaration of your class inherits another class, or when it declares that it conforms to a given #protocol (like delegate protocols and so on), because in this particular case, the compiler needs you to #import the whole definition of the parent class or #protocol (to know if your class correctly conforms to this given protocol).
MyClassA.h
// Tells the compiler that "MyClassB" is a class, that we will define later
#class MyClassB; // no need to #import the whole class, we don't need to know the whole definition at this stage
#interface MyClassA : NSObject {
MyClassB* someB; // ok, the compiler knows that MyClassB is a class, that's all it needs to know so far
}
-(void)sayHello;
-(void)makeBTalk;
#end
MyClassB.h
#class MyClassA; // forward declaration here too
// anyway we couldn't #import "MyClassA.h" here AND #import "MyClassB.h" in MyClassA.h as it would create an unsolvable import loop for the compiler
#interface MyClassB : NSObject {
MyClassA* someA; // ok, the compiler knows that MyClassA is a class, that's all it needs to know so far
}
-(void)talk;
-(void)makeABePolite;
#end
MyClassA.m
// import MyClassB so that we know the whole definition of MyClassB, including the methods it declares
#import "MyClassB.h" // thus we here know the "-talk" method of MyClassB and we are able to call it
#implementation MyClassA
-(void)sayHello { NSLog(#"A says Hello"); }
-(void)makeBTalk {
[someB talk];
// we can call the 'talk' method because we #imported the MyClassB header and knows this method exists
}
#end
MyClassB.m
// import MyClassA so that we know the methods it declares and can call them
#import "MyClassA.h"
#implementation MyClassB
-(void)talk { NSLog(#"B is talking"); }
-(void)makeABePolite {
[someA sayHello];
// we can call this because we #import MyClassA
}
#end
PS: Note that if this is a best practice, I know a lot of developers (including myself sometimes ^^) that #import the header it needs in their .h files, instead of only forward-declare it using #class... this is some bad habit — or because these developers doesn't know these subtleties — that you will unfortunately encounter in existing code anyway.
Using #class is called forward declaration. Since usually you don't need to know the specifics of the class in the .h file, this is usually all you need.
Forward declaration prevents you getting into a situation where you import a particular .h file, which says to import another .h file, which says to import the original .h file again, and so on.
The #class forward declaration allows you to have your interfaces behave like interfaces. Meaning: Declare your code.
But this doesn't mean that you can leave out the #import statement. You just moved the responsibility to the implementation to import and make use of it.
Basically it could be seen as an increase in performance as you're not importing any other headers inside your current header.
Important Note: This isn't the case when you're working with delegates.
If you're making use of delegates you always have to have the proper #import statements in place so that the compiler knows which delegate methods are to be implemented by that class.
You might also want to have a look at the following SO question: #class vs. #import

#import statements in .m or .h in objective-c?

I ended up having these in both of my .h and .m files, this is my first Objective-C program so I'd like some clarification so I can clean thins thing up.
Unless it affects the interface definition you should put it in the .m file.
If you just use a class, use a forward declaration:
#class AClass;
#interface Bob : NSObject {
AClass* a;
}
If you implement something, then import it:
#import "SomeProtocol.h"
#interface Bob : NSObject<SomeProtocol> {
}
These kinds of thing are really "best practice" rather than absolutely essential. Objective C's #import directive means that you can't get errors because you include a file multiple times, so it's not technically a problem, but it will increase compile times.
These are the rules I follow:
If in your header file, you only need to use pointers to classes declared in the header file you are including, then I would just use a class sentence on the header file (.h) and full import on the definition (.m) file.
If you need to use full definition of some stuff on the header file you are including, then the full import goes into the header file.
For the examples, consider files MyClass.m, MyClass.h and MyInclude.h:
Example, scenario #1:
// MyClass.h
#class MyInclude;
#interface MyClass : NSObject {
MyInclude *myIncludeObj;
}
// MyClass.m
#import "MyClass.h"
#import "MyInclude.h"
Exaple, scenario #2:
// MyClass.h
#import "MyInclude.h"
#interface MyClass : NSObject {
MyInclude myIncludeObj; // MyInclude could be a plain C structure
}
// MyClass.m
#import "MyClass.h"
The #import directive is an improvement over the #include directive in that instead of blindly copying the file in place, it will not include it if it has already been included. Therefore you shouldn't experience any problems with #import-ing the same file multiple times.
As far as best practice goes, IMHO it's best to keep the scope as narrow as possible. Therefore I'd suggest putting your #imports in you implementation files (.m). If you require the class definition in your interface file (.h) then you can use the
#class MyClass;
construct to inform the compiler that it will be able to find the relevant header in the implementation file.
Hope this helps.
I have just one rule: Import at the top of the .h file for the superclass and protocols of any classes you declare in the .h file. This is because any file that imports your .h file also needs the declarations for the superclass and protocols. This is also why the default Xcode template has #import <UIKit/UIKit.h> in the .h file rather than the .m file.
For everything else (e.g. types used for ivars and method parameters), use forward-declarations and put the #import in the .m file
Another way to put this is: never use forward declarations for superclasses and protocols.
Best practices is to put #import statements in .m files. If you need access to a class inside the header file, for a property declaration or a function parameter, use a forward declaration, like this:
#class Cocos2DController;
#interface HoppersAppDelegate : NSObject <UIApplicationDelegate> {
Cocos2DController* controller;
}
A forward declaration lets the system know that the class exists, though it's not yet fully defined. With this pattern, you'll keep your headers lean, and guarantee that you're only importing the headers that you want for a specific class, not chaining #imports all through the application.
For a specific problem you might run into: If you include #import statements in a header file, you run the risk of an #import loop if two classes import each other's header files.

when and where to put #class declarations

I am working on a project with several custom classes. I have a CardModel (NSObject) that has some integer properties to hold data, and a Deck (NSObject) that has an array to hold a bunch of CardModels and then a CardView (UIView) that has a CardModel as a property that I make when I select a CardModel from a Deck. And then I've got a bunch of UIViewControllers that I move around on a UINavigationController.
My question is about where and when to use the #class compiler directive.
If I subclass a UIViewController by making a new file and subclassing it, should I use the #class MyViewController in the header of MyViewController.h or .m and does it go in the header of the file that actually uses the controller (like when one controller is going to instantiate another controller type and push it to the stack). Or do I need to use it at all? Is it only required if I actually add new properties to my class beyond what's in the stock implementation? It seems like I'm putting #class all over the place just make sure I don't get errors but I don't fundamentally understand when I need it.
Thanks!
You use it in the .h to inform it about a custom class without including the .h for the custom class.
Example:
Two custom classes: Car and Wheel
Car.h
----------------
#interface Car : NSObject {
}
- (void)addWheel:(Wheel*)newWheel;
#end
Car.h doesn't know about the class 'Wheel' so it would throw an error so you could import the Wheel.h like so:
Car.h
----------------
#import "Wheel.h"
#interface Car : NSObject {
}
- (void)addWheel:(Wheel*)newWheel;
#end
BUT you dont need to do this either. Car.h doesn't need to know anything about the Wheel class, it just needs to know it exists. So what you use is the #class to just say that "Hey, this class exists. Take my word for it."
Car.h
----------------
#class Wheel;
#interface Car : NSObject {
}
- (void)addWheel:(Wheel*)newWheel;
#end
Then inside of the Car.m, when you actually need to know about the Wheel class (properties, methods, etc) you should import the Wheel.h there.
The #class directive is used when you need a header to know about a class but you don't want to import the class's header file; e.g., when you need to avoid circular dependencies.

My protocol method is not triggered, and no errors while trying

First time working with protocols and it is not working but no errors either...
I have defined and implemented a protocoll in a delegate (BlockPopViewController). Then I try to access it from a UIViewController (BoardViewController) whose view has been added to the delegate as a subview.
The result is that my request to the protocol's method is not creating any errors, but the method is not triggered either. Would be most appreciated if someone has an idea. Thanks in advance!
BlockPopViewController.h
#import "DirectionViewController.h"
#class BoardViewController;
#protocol BVCProtocol
- (void)testing;
#end
#interface BlockPopViewController : UIViewController <BVCProtocol> {}
-(void)testing;
#end
BlockPopViewController.m
#implementation BlockPopViewController
-(void)testing{
NSLog(#"Testing in delegate BlockPopViewController");
}
#end
BoardViewController.h
#class BoardView; //This I cannot import, I think this should be ok instead. Probably cyclic import...
#class Bric; //This I cannot import, I think this should be ok instead. Probably cyclic import...
#protocol BVCProtocol;
#interface BoardViewController : UIViewController {
}
#property(nonatomic, assign) id <BVCProtocol> blockPopViewController;
#end
BoardViewController.m
#import "BlockPopViewController.h"
#import "BoardViewController.h"
#implementation BoardViewController
#synthesize blockPopViewController;
-(void)touchesEnded:(NSSet*)touches withEvent:(UIEvent *)event{
NSLog(#"INSIDE TOUCHESENDED");
[[self blockPopViewController] testing];
}
You are missing a declaration of your BlockPopViewController class which says that BlockPopViewController implements the BVCProtocol protocol.
You should also have your implementation of BVCProtocol derive NSObject in order to get proper memory management behavior. Additionally, you should derive all your protocols from the NSObject protocol in order to prevent compiler warnings when you use NSObject messages on instances of your protocol implementation.
In BlockPopViewController.h you need:
#protocol BVCProtocol <NSObject>
- (void) testing;
#end
#interface BlockPopViewController : UIViewController <BVCProtocol>
#end
In BoardViewController.h you must also #import "BlockPopViewController.h". Otherwise, the compiler won't know anything about the fact that BlockPopViewController is implementing BVCProtocol nor anything about BVCProtocol to begin with.
It would be more logical to declare a protocol in its own .h file and to import that in .h file declaring an implementation of the protocol.
You might find this little tutorial helpful.
Declare protocol outside #interface ... #end context
#protocol BVCProtocol
- (void) testing;
#end
#interface BlockPopViewController : UIViewController <BVCProtocol>
//...
#end
I think the problem I had was that I didn't create an instance of "BlockPopViewController". I changed my solution to not use protocols since it seems like overkill for me. I do have full controll of all involved classes and don't get any benefits using protocols. I do however think that this is what caused it to not work. If there is a reason for using protocols in this kind of situation which I am not aware of, pleas fill me in...
Also see Apple's Communicating with Objects, which discusses delegates, protocols, and selectors. Though its listed under Mac OS X, most (if not all) appears to apply to iOS also.