I have two view controllers A and B, and they both have each other as their delegates.
When I did nothing except define the protocols at the beginning of the header files and #import the other's header file, I got two errors along the lines of -
cannot find protocol declaration for "BDelegate", which was showing in
A.h (where I wrote ) cannot find protocol declaration for
"ADelegate", which was showing in B.h (where I wrote )
Looking online, people had written earlier that the circular inclusion of header files could be leading to the problems. They recommended either using #include instead, or #class declaration like -
#class A
instead of
#import A.h
inside #import B.h
I have tried almost every combination of these imports, and #classes, and #include but still can't get rid of the warnings. Also, solutions online recommended moving the #import to the .m files but that didn't help either. Part of the reason is that the solutions online are kinda fuzzy - if you could break it down that would be great.
Any suggestions about what can be done to fix this?
-- BigViewController.h --
#import "BaseViewController.h"
#include "BaseViewController.h"
#class BigViewController;
#protocol BigViewControllerDelegate
-(void) BigViewController:(BigViewController *) bigView;
#end
#interface BigViewController : UIViewController <BaseViewControllerDelegate>
{
//delegate
id <BigViewControllerDelegate> delegate;
ivars...
}
#properties...
#end
--------------------------------------------------
-- BaseViewController.h --
#<UIKit/UIKit.h>
#import "BigViewController.h"
#include "BigViewController.h"
#class BigViewController;
#protocol BaseViewControllerDelegate
- (void) setParametersWithItemChosen:(Item *) item;
#end
#interface BaseViewController : UIViewController <...BigViewControllerDelegate...>
{
ivars...
//delegate
id <BaseViewControllerDelegate> delegate;
}
#properties...
#end
Let me reduce the sample even further, and label the lines:
VC1.h
#import "VC2.h" // A
#class VC1;
#protocol VC1Delegate // B
#end
#interface VC1 : UIViewController <VC2Delegate> // C
#end
VC2.h
#import "VC1.h" // D
#class VC2;
#protocol VC2Delegate // E
#end
#interface VC2 : UIViewController <VC1Delegate> // F
#end
Consider what happens when something #imports VC1.h: It reaches line A, then the import is processed. Line D does nothing because VC1.h was already imported. Then line E is processed. Then line F, and we get an error because we haven't gotten to line B yet so the protocol is not declared!
Consider then what happens when something #imports VC2.h: It reaches line D, then the import is processed. Line A does nothing because VC2.h was already imported. Then line B is processed. Then line C, and we get an error because we haven't gotten to line E yet so the protocol is not declared!
The first step is to reconsider whether both of these classes really need to be each other's delegates. If you can break the cycle, that would probably be the way to go. If not, you'll need to restructure your headers. The most straightforward way is probably to put the delegates into their own headers:
VC1Delegate.h
#class VC1;
#protocol VC1Delegate // B
#end
VC1.h
#import "VC1Delegate.h"
#import "VC2Delegate.h"
#interface VC1 : UIViewController <VC2Delegate> // C
#end
VC2Delegate.h
#class VC2;
#protocol VC2Delegate // E
#end
VC2.h
#import "VC1Delegate.h"
#import "VC2Delegate.h"
#interface VC2 : UIViewController <VC1Delegate> // F
#end
If you trace through the imports now, you'll see that the appropriate protocols will now always be declared before the #interface lines try to use them.
Write protocol declaration code above the #import lines
e.g.
#protocol -----
#end
import ----
#interface classname ---
I had almost the same problem, and I fixed it thanks to the answer above, but in a slightly different way.
all I did was to put the #import line after the protocol declaration in the header file.
hope I can help. and if anyone know that this is bad programing for some reason, pls let me know
I found another solution to this issue because I didn't really like the idea of just having some #imports in between the class and the protocol declaration.
Basically you just move <YourProtocolName> from the .h class file to the class extension in the .m file
So in your .m file you add
#interface YourClassName () <YourProtocolName>
#end
I don't know if this is really a good practise but it looks like a cleaner solution to avoid the import cycles.
Try putting the < BaseViewControllerDelegate > or < BigViewControllerDelegate > in implementation file rather then header file. It will work.
I followed the fix of moving the protocol before the import and it fixed the problem... the import included the delegate, so that was causing the problem.
But then I thought, why was I importing the delegate anyway? I wasn't referencing its properties and I wasn't calling any of its methods directly (that's what the protocol declare was for).
I tried commenting out the import of the delegate and saw where the error came up and found that what I was importing when I was importing the delegate was actually a declaration that the delegate was importing i.e. I was importing A (also my delegate), A was importing B, what I was actually using was B. So I left the import of A commented out and added an import for B. Then I could put the import-protocol order back the way it was.
Related
I have created a NSCollectionViewItem subclass, called TSCollectionViewController. It overrides one method, setRepresentedObject:. I plan on using it in my NSView, TSTopChartView. Oddly enough, I get an error when I add it to the TSTopChartView.h file (pictured below).
Obviously, Xcode doesn't like TSCollectionViewController for this file. I just can't figure out why! I've imported the file, so it shouldn't be an unknown type name. Any ideas? Thank you for your time!
Here is TSCollectionViewController.h:
#import <Cocoa/Cocoa.h>
#import "TSTopChartCell.h"
#import "TSPodcastEpisodeCell.h"
#import "TSDetailView.h"
#interface TSCollectionViewController : NSCollectionViewItem
#end
You have a circular #import dependency between TSCollectionViewController.h and TSTopChartView.h. In your case you can break it easily by removing #import "TSTopChartCell.h" from TSCollectionViewController.h.
If you end up in a case where you really need the class TSTopChartCell to be declared in TSCollectionViewController.h you can fix this by adding #class TSTopChartCell instead of the #import "TSTopChartCell.h". Then you can actually #import "TSTopChartCell.h" in the implementation file, TSCollectionViewController.m.
Since I had a import-cycle recently, I'm moving all #import statements (concerning my own files) from the header into the corresponding .m-file. I also added #class and #protocol forward-declarations to soothe the compiler. However, I still get he following warning:
Cannot find the protocol definition for 'MyCustomDelegate'.
As I said, there is an #protocol MyCustomDelegate before I use it in the #interface-Block. Interestingly this warning only occurs if the corresponding delegate is declared in another file (whose header is imported in the .m-file).
I read that one solution is to declare the delegate in a separate header file and import that file directly in the header of the class that implements the delegate. Is this really the way to go? Are there any other solutions? I think those delegates already bloated our code enough, now I should go on and even declare an own file for it?
Small sample code to better illustrate the problem:
NewFooController.h
#import <UIKit/UIKit.h>
#protocol NewFooControllerDelegate;
#interface NewFooController : UITableViewController
#property (nonatomic, weak) id<NewFooControllerDelegate> delegate;
#end
#protocol NewFooControllerDelegate
#end
HomeTableViewController.h
#import <UIKit/UIKit.h>
#protocol NewFooControllerDelegate;
// warning points to line below
#interface HomeTableViewController : UITableViewController <NewFooControllerDelegate>
#end
HomeTableViewController.m
#import "HomeTableViewController.h"
#import "NewFooController.h"
#implementation HomeTableViewController
#end
HomeTableViewController.h references the protocol, but it hasn't been declared yet.
If you import NewTaskController.h in HomeTableViewController.h before it attempts to use it, it should solve your problem.
Of course you can then remove the import from HomeTableViewController.m
Not sure if this is "best way", but try import header of class that implement protocol before class header file.
HomeTableViewController.m
#import "NewFooController.h"
#import "HomeTableViewController.h"
#implementation HomeTableViewController
#end
And you can remove protocol declaration in HomeTableViewController.h
#import <UIKit/UIKit.h>
#interface HomeTableViewController : UITableViewController <NewFooControllerDelegate>
#end
I am trying to #import my "AppDelegate.h" into another header file of the same project in order to access methods of the AppDelegate of my iOS project.
So, my header file looks something like this:
#import
#import "DataProvider.h"
#import "MyAppDelegate.h"
#interface MyViewController : UIViewController <UITextFieldDelegate, UIAlertViewDelegate> {
...
}
and I want to use my AppDelegate like this:
MyAppDelegate* appDelegate = (MyAppDelegate*)[UIApplication sharedApplication].delegate;
[appDelegate doSomething];
However, as soon as I #import "MyAppDelegate.h", the compiler throws a lot of (unrelated) errors, like
Cannot find interface declaration for 'MyOtherViewController', superclass of 'MyOtherViewController2'
The thing is: I can include my AppDelegate just fine in other headers. And I cannot figure out what the difference might be. Please help me figure out what could cause this! Thanks a lot!
PS: This happens with GCC as well as the new LLVM.
Move the #import into the .m file. If you need the MyAppDelegate symbol in your .h, use #class MyAppDelegate; instead.
This question already has answers here:
Closed 11 years ago.
Possible Duplicate:
How can I have references between two classes in Objective-C?
Objective-C #import loop
I'm getting a couple errors in my code and I'm not sure but I think its because I'm #importing an interface inside another interface where I'm #importing the other interface. If I'm confusing you I'll give you an example.
#import "OneClass.h"
#interface SecondClass : NSObject
{
OneClass * obj;
}
#import "SecondClass.h"
#interface OneClass : NSObject
{
SecondClass * obj;
}
Yes, you have a circular import. The problem here is that the second import (the one that re-imports your first header) is basically ignored by the compiler, since it thinks it's already imported that header.
The solution here is to use #class forward-declarations instead of using #imports. Not only does this solver the circular import problem, but it's a better idea anyway since it breaks unnecessary dependency chains (e.g. if I edit OneClass.h, SecondClass.h won't need to be re-processed).
To apply this here, simply remove the #import OneClass.h in SecondClass.h and replace it with #class OneClass;
In the more general case, you don't ever need to #import a header file just to declare an ivar/property/method that uses a class from that header. The #class token is sufficient. You do, however, need to #import the header file if you're inheriting from the class, or if you're referencing another non-class type declared in that header. Also remember that if you use #class in your header, you need to remember to put the actual #import into your .m file.
If you're importing a header file you need to put the full file name. In this case...
#import "SecondClass.h" instead of #import "SecondClass"
You can declare the use of a class without having to #import its associated header, like so:
// #import "SecondClass.h" // no need for this anymore
#class SecondClass;
#interface OneClass : NSObject
{
SecondClass * obj; // OK
}
When there are no physical dependencies, you should be using forward declarations to minimise your build times:
// SecondClass.h
#class OneClass;
#interface SecondClass : NSObject
{
OneClass * obj;
}
#end
// OneClass.h
#class SecondClass;
#interface OneClass : NSObject
{
SecondClass * obj;
}
#end
It also happens to fix your dependency cycle ;)
I have two classes ClassA and Class B (they are viewControllers).
Class A is a delegate of classB.
ClassA "laucnhes" and instance of ClassB.
ClassB call methods on classA.
Let's say it's :
#import "ClassB.h"
#interface ClassA : NSObject {
ClassB* subController;
}
- (void) doThis;
-------------------------------
#import "ClassA.h"
#interface ClassB : NSObject {
ClassA* delegate;
}
-------------------------------
#implementation ClassB
- (void) someMethod {
AnObject* myObj = [self.delegate.arr objectAtIndex:8];
[self.delegate doThis];
}
Doing that way, A must import B, and B must import A.
If B do not import A (with just #class A), there is a compile error for the used attribute from A.
If B imports A, there is a compile error on the ClassA* delegateline.
Why do I have those compile errors? Doesn't #import protect again recursive calls ?
I don't need a solution to solve that problem, I know how I may do this.
But I wonder why my #import cause those problems. These are not #includes...
In .h files prefer #class to #import. Both can then be imported in the .m implementation files.
// ClassA.h -------------------------------
#class ClassB;
#interface ClassA : NSObject {
ClassB* subController;
}
- (void) doThis;
// ClassB.h -------------------------------
#class ClassA;
#interface ClassB : NSObject {
ClassA* delegate;
}
// ClassB.m -------------------------------
#import "ClassA.h"
#import "ClassB.h"
#implementation ClassB
- (void) someMethod {
AnObject* myObj = [self.delegate.arr objectAtIndex:8];
[self.delegate doThis];
}
Using #class statements instead of #import also reduces dependencies and makes the remaining ones more clear. It can also speed up compile times.
Why do I have those compile errors? Doesn't #import protect again recursive calls ?
#import protects against repeatedly importing the same header into the same module, whether by circular includes/imports or not. It protects against that by not letting you do it: Only the first #import of a header works; subsequent #imports of the same header are ignored.
In a circular #include situation, the preprocessor would go around the circle some number of times and then fail the build before you even get to compilation. Using #import prevents the preprocessor from getting wedged and lets the preprocessor succeed, but circular-#import code is still dodgy at best and usually will not compile.
So, on to your specific situation.
For the code you showed in your question, #class will work in either or both headers, and indeed you should use it in both. You'll also need to #import both headers in both .m files.
If B do not import A (with just #class A), there is a compile error for the used attribute from A.
If you mean “there is a compile error at each point where I use that attribute of type ClassA *”, then yes: You can't talk to that object because you haven't imported its interface, so the compiler doesn't know what messages you can send to a ClassA instance. That's why you need to import its interface.
If B imports A, there is a compile error on the ClassA* delegateline.
If both headers import each other, then you have this:
ClassA.m:
ClassA.h
ClassB.h
ClassA.h (ignored because this was already imported by ClassA.m)
ClassB.m:
ClassB.h
ClassA.h
ClassB.h (ignored because this was already imported by ClassB.m)
There is no way this can work without one interface preceding the other without the other interface preceding it. That's the circle you're running into—the circle that #import exists to break. #include allows the circle, and thereby gets wedged:
ClassA.m:
ClassA.h
ClassB.h
ClassA.h
ClassB.h
ClassA.h
ClassB.h
ClassA.h
ClassB.h
ClassA.h
ClassB.h
ClassA.h
ClassB.h
(fails at some point)
Hence #import.
So you cannot import each header from the other. Hence #class.
But you still need to import each header from each module. That is, in fact, exactly what you need to do: Use #class in each header and use #import (on both headers) in each module.
This compile complaint can be avoided by declaring
#class ClassB;
in the .h file. The ClassB.h can then be included into the .m file.
So you are right on that one. Contrary to urban myth, #imports work pretty much like #includes in the sense that the compiler has to check the file.
See this (duplicate?) question for your philosophical problem.
I think you'll find that #import only protects against multiple inclusion once it has already been successfully included once, so to speak.
ie, in your case, it hasn't successfully imported classa.h before it is asked to import it again, so it does so.