9

When I compile with the following code there are no errors:

@class RootViewController;
//#import "RootViewController.h"

When I compile with the following code I get an error:

//@class RootViewController;
#import "RootViewController.h"

"error: expected specifier-qualifier-list before 'RootViewController'"

I don't understand what the difference is between the two because I used #import in a similar class and it compiled without errors!

TheLearner
  • 19,387
  • 35
  • 95
  • 163
  • 1
    In your case, there is something wrong in your RootViewController.h file, or one of the files that it imports. Maybe a missing ";" somewhere. It's unfortunately a bit hard to debug header files because you often get the error in another file. The reason you don't get the error when you use @class is that it doesn't load the file containing the error. See my answer for more details. – Felixyz Jul 29 '10 at 10:29
  • possible duplicate of [Objective-C @class vs. #import](http://stackoverflow.com/questions/322597/objective-c-class-vs-import) – willcodejavaforfood Jul 29 '10 at 16:05

8 Answers8

32

@class is used when you need to know the name of a class in a particular file, but you don't need to know any details about the class (its methods, for example). #import is used when you actually need to use the class (i.e., send it a message).

For example, if you're declaring instance variables in a header file, you can use @class to declare an instance variable of a certain type:

@class MyOtherClass;

@interface MyClass : NSObject
{
    MyOtherClass *myIvar;
}
@end

Since you're not using myIvar yet, you don't need to know anything about it except that the type MyOtherClass exists.

However:

#import "MyOtherClass.h"

- (void)doSomething
{
    [myIvar doSomethingElse];
}

In this case, you're sending the doSomethingElse message to myIvar; the compiler needs to know that instances of MyOtherClass define this method, so you have to import the header file or the compiler will complain.

Why worry about this?

It mostly has to do with dependencies. When you #import file A into file B, file B becomes dependent upon file A -- that is, if file A changes, you'll have to recompile file B. If you use @class in file B, file B is not dependent on file A, and thus doesn't need to be recompiled when file A changes -- so if you're just declaring a type and not actually dependent upon the implementation of file A, you can save yourself compilation time by not #importing file A.

mipadi
  • 398,885
  • 90
  • 523
  • 479
8

I decided to refer to the documentation because I was still confused:

#import

This directive is identical to #include, except that it makes sure that the same file is never included more than once. It’s therefore preferred and is used in place of #include in code examples throughout Objective-C–based documentation.

This convention means that every interface file includes, indirectly, the interface files for all inherited classes. When a source module imports a class interface, it gets interfaces for the entire inheritance hierarchy that the class is built upon.

@class

Declarations like this simply use the class name as a type and don’t depend on any details of the class interface (its methods and instance variables), the @class directive gives the compiler sufficient forewarning of what to expect. However, where the interface to a class is actually used (instances created, messages sent), the class interface must be imported.

http://developer.apple.com/iphone/library/documentation/Cocoa/Conceptual/ObjectiveC/Articles/ocDefiningClasses.html#//apple_ref/doc/uid/TP30001163-CH12-TPXREF123

TheLearner
  • 19,387
  • 35
  • 95
  • 163
  • BTW in case you're wondering why I have not accepted an answer - its because this system doesn't allow me to accept answers until 2 days have passed - heaven knows why this is needed – TheLearner Jul 30 '10 at 08:03
7

Basic rule: use @class in you header file and #import in your implementation file. (However, you need to #import your class' superclass. And in some other circumstances you also need to use `#import" in the header.)

#import is not equivalent to #include. If a file is included many times, it will be loaded each time, but with many #imports of the same file, it will still only be loaded once.

Therefore, the main reason to use @class is not to avoid circular dependencies, but to make compilation faster.

Here's an example of when you must use @class

//MYControl.h

@class MYControl;  // Must use class

@protocol MYControlDelegate
-(void)control:(MYControl *)control didChangeToState:(UIControlState)state;
@end

@interface MYControl : UIControl
{
   id<MYControlDelegate> delegate_;
}
@property (nonatomic, assign) id<MYControlDelegate> delegate;
@end

//MYControl.m

@implementation MYControl
@synthesize delegate = delegate_;
. . .

In this case, there is nothing to import, because the delegate protocol is declared above the main class in the header file. But you still need to be able to refer to the main class which has not yet been declared. So what @class does is to just let the compiler know that there is some class that is called MYControl and will be defined at some point. (Not at runtime however. The class will be defined in the course of the compilation.)

EDIT: From the Objective-C manual:

Since declarations like this simply use the class name as a type and don’t depend on any details of the class interface (its methods and instance variables), the @class directive gives the compiler sufficient forewarning of what to expect. However, where the interface to a class is actually used (instances created, messages sent), the class interface must be imported. Typically, an interface file uses @class to declare classes, and the corresponding implementation file imports their interfaces (since it will need to create instances of those classes or send them messages).

The @class directive minimizes the amount of code seen by the compiler and linker, and is therefore the simplest way to give a forward declaration of a class name. Being simple, it avoids potential problems that may come with importing files that import still other files. For example, if one class declares a statically typed instance variable of another class, and their two interface files import each other, neither class may compile correctly.

Note that circularity is mentioned in the last sentence as one in a general class of issues dealt with by using @class.

Felixyz
  • 19,053
  • 14
  • 65
  • 60
  • Why do you say @class is not to avoid circular dependencies and then provide an example in which it is used in precisely that manner? In your example, the `MyControl` class has a dependency on the `MyControlDelegate` protocol and `MyControlDelegate` has a dependency on `MyControl`. – JeremyP Jul 29 '10 at 14:30
  • By the way your declarations of variables and properties of the delegate type are wrong. They should be like this: `id delegate_;` – JeremyP Jul 29 '10 at 14:31
  • @JeremyP: about ivar/property declaration: thanks, I've corrected it. About the circularity issue, I said circular references are not the *main* reason for the existence of @class. Rather the purpose of @class is to reduce references of *any* kind to speed up compilation. Circular references can also be handled in other ways, although @class is handy in this respect too. I think these statements are reflected in the quote I've added to my answer. Having pointed that out, nothing prevents me from showing an example where @class helps deal with a circular reference (within one file). – Felixyz Jul 30 '10 at 13:44
  • I think you are wrong. Speed of compilation is not a reason I've ever heard of before for using @class. Perhaps you can provide a citation. – JeremyP Jul 30 '10 at 22:01
  • 1
    Compilation speed is the *biggest* reason I've heard for using `@class`. – mipadi Aug 03 '10 at 16:26
6

@class is used to avoid circular dependency... This prevents circular references where in one header A imports a second header B which(B) imports the first(A) which imports the second (B)and so on in an endless cycle....@class is generally used to ask compiler to look for its definition at runtime... especially when it resides in some static library..

Other than that #import works

See this question

Community
  • 1
  • 1
Mihir Mehta
  • 13,743
  • 3
  • 64
  • 88
  • 3
    I disagree that @class is mostly used to avoid circular references, because #import already takes care of that. (Try it!) – Felixyz Jul 29 '10 at 10:30
  • ok disagreement accepted... @class is generally used to ask compiler to look for its definition at runtime... especially when it resides in some static library... – Mihir Mehta Jul 29 '10 at 10:35
  • 1
    @Felixyz: sorry but you are wrong. The main use of @class is to avoid circular depndencies of @interface and @protocol definitions. – JeremyP Jul 29 '10 at 14:27
  • @JeremyP: I was wrong to say that "#import already takes care of that", because it doesn't always. However, I think it's exaggerated to say that @protocol definitions are the "main use" of @class. In the quote I've added in my answer there is no mention of @protocol, for example. – Felixyz Jul 30 '10 at 13:47
  • @Felixyz: I didn't mean that. I meant that the use of @class is to avoid circular dependencies of @interfaces and it's also used to avoid circular dependencies of @protocols, and combinations of the two. – JeremyP Jul 30 '10 at 21:59
  • That's it's main use, I was using only #import and ignoring @class , until I had problems with circular imports. – Ramy Al Zuhouri Apr 06 '13 at 10:57
2

@class:- It defines that you can create instance variable of the imported class and use it in your class.

import:- It defines that you can access the variables declared in the required imported class.

you can use given link for more info.

http://developer.apple.com/iphone/library/documentation/Cocoa/Conceptual/ObjectiveC/Articles/ocDefiningClasses.html#//apple_ref/doc/uid/TP30001163-CH12-TPXREF123

Community
  • 1
  • 1
Programming Learner
  • 4,351
  • 3
  • 22
  • 34
0

you must have imported the this class in the class to which you want to import here. That is why you are getting error , but it can be rectify by @class example .

Sachin Siwal
  • 311
  • 1
  • 3
  • 13
0

@class is a forward declaration, a good practice is to put them in the .h instead of #import for avoiding circular #import problem.

0

@class means that the definition of the class RootViewController is not yet declared, but will be defined at run time. I believe it is like declaring an extern class in c++.

#import is equivalent to #include.

by the error message i could guess you just made a mistake somewhere inside RootViewController.h, such as a forgotten ; or something like that

koda
  • 741
  • 1
  • 7
  • 18
  • 1
    It's not correct to say that it "will be defined at run time". The class will definitely be defined at some point during the compilation. In fact, it might already be defined. @class just says that in the context of this file, we are not going to access any of the fields or methods of the class, so all we need to know is its name so we can declare pointers to it. – Felixyz Jul 29 '10 at 10:33