2

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;
}
Community
  • 1
  • 1
Jordan Medlock
  • 807
  • 1
  • 8
  • 21
  • Also, is the sample above actually two separate files? As you have it one might interpret the whole block to reside within a single file... if they are separate, what are the names of the files in which the blocks live? – fbrereto Nov 30 '11 at 23:23

4 Answers4

2

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.

Lily Ballard
  • 182,031
  • 33
  • 381
  • 347
1

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"

Mark Adams
  • 30,776
  • 11
  • 77
  • 77
  • That certainly is a bug with his code as-written, but I suspect what he wrote here is pseudocode and that's not actually the bug with his "real" code (the bug there is a circular dependency). – Lily Ballard Nov 30 '11 at 23:26
  • I thought the whole reason we use #import instead of #include is because it is smart enough to handle circular dependencies? – Mark Adams Nov 30 '11 at 23:31
  • 1
    NO it does not handle circular dependencies, it does handle multiple inclusions, there is no need for the usual C/C++ #ifdef guards. – zaph Nov 30 '11 at 23:33
  • I'm not arguing that #importing header files in .h files is sub-optimal. I'm simply trying to understand why #import usually takes precedence over #include. I know that #import guarantees that a header will only be included once. I fail to see how this creates a circular dependancy though. – Mark Adams Nov 30 '11 at 23:34
  • @MarkAdams: A circular #include will loop forever. An #import is precisely equivalent to an #include with import guards (or with `#pragma once`), although it's probably more efficient. But it doesn't solve the circular dependency problem. That problem *cannot* be solved with trickery around includes. The only way to solve it is to avoid the circular include to begin with, typically via forward-declarations, which is what `@class` is here. – Lily Ballard Nov 30 '11 at 23:51
1

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
    }
fbrereto
  • 35,429
  • 19
  • 126
  • 178
  • Whenever possible this is the preferred method, that is forward @class declarations i the .h instead of #import. The .m will have to have an #import though. – zaph Nov 30 '11 at 23:34
1

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 ;)

justin
  • 104,054
  • 14
  • 179
  • 226
  • what do you mean by physical dependency? – Jordan Medlock Dec 04 '11 at 00:30
  • a forward declaration does not have physical dependence, it's really just a name/label -- specifically, the variable to be legally declared in the header without the declaration (`@interface`) visible prior to its usage. Contrast: both classes have a physical dependence on NSObject (via inheritance) -- if Foundation is not included prior to the class declaration, then it is an error. Of course, you would still need to include OneClass.h into SecondClass.m when using a forward (in the majority of cases). – justin Dec 04 '11 at 06:20
  • Oh ok I get it thanks! this helped me realize there was a more fundamental flaw that made this hard – Jordan Medlock Dec 05 '11 at 15:34