I have the following project structure:
Main.h
Son1.h
Son2.h
They're not related (no father/son relationships), just two imports, like in Main.h I have:
#import Son1.h
#import Son2.h
If, from another file I write
#import Main.h
I will see all the methods/properties of Main.h (and that's ok) but I will also see the methods of Son1.h and Son2.h.
How can I prevent this?
It's important to understand what #import (and the C version: #include) do.
Compilation of C programs conceptually have 3 steps:
Preprocessing
Compiling
Linking
The directives beginning with # are acted on by the preprocessor (it doesn't matter at all whether this is a separate binary or part of the compiler). Both of these statements cause the contents of the named file to inserted into the importing (or including) file at the point where the directive is found. This is completely language-agnostic. The imported file can have anything in it. You can import a JPG, if you want (but good luck compiling!).
In your example, by importing Son1.h and Son2.h in Main.h, you are creating, from the compiler's perspective, a single file with the contents of Son1.h followed by the contents of Son2.h followed by whatever is in Main.h itself. At this level, the idea of hiding content doesn't make sense. You explicitly asked the preprocessor to put those contents there. It doesn't know anything about the text it's inserting, so it can't follow any kind of Objective-C directive, even if such existed.
The comments are getting to another point. Importing in a .h should be kept to an absolute minimum. The most common reasons to import are for class and protocol type definitions, and Objective-C allows you to forward declare both of these precisely to avoid otherwise necessary imports.
If you have something like:
#interface MyClass : NSObject
#property(nonatomic, strong) MyOtherClass *myOtherClass;
#end
You normally would have to #import "MyOtherClass.h". However, with forward declarations, you can do this instead:
#class MyOtherClass;
And move the #import to the implementation file, which is generally hidden from other files.
I'm integrating Swift code into a large Objective-C project, but I'm running into problems when my Swift code refers to Objective-C classes. For example, suppose I have:
An Objective-C class called MyTableViewController
An Objective-C class called DeletionWorkflow
I declared a Swift class as follows:
class DeletionVC: MyTableViewController {
let deleteWorkflow: DeletionWorkflow
...
}
If I now try to use this class by importing ProjectName-Swift.h into Objective-C code, I get undefined symbol errors for both MyTableViewController and DeletionWorkflow.
I can fix the problem in that individual source file by importing DeletionWorkflow.h and MyTableViewController.h before I import ProjectName-Swift.h but this doesn't scale up to a large project where I want my Swift and Objective-C to interact often.
Is there a way to add forward class references to ProjectName-Swift.h so that these errors don't occur when I try to use Swift classes from Objective-C code in my app?
You can create another header file that forward declares or imports the necessary classes, and then imports ProjectName-Swift.h. For example, create a file named ProjectName-Swift-Fixed.h with the contents:
// ProjectName-Swift-Fixed.h
// Forward declarations for property classes
#class DeletionWorkflow;
// Imports for superclasses
#import "MyTableViewController.h";
#import "ProjectName-Swift.h"
Then, instead of #import "ProjectName-Swift.h" in your codebase, use #import "ProjectName-Swift-Fixed.h.
This is a little silly, but it sounds like your "workaround" is what Apple intended, at least for now. From the interoperability guide:
If you use your own Objective-C types in your Swift code, make sure to import the Objective-C headers for those types prior to importing the Swift generated header into the Objective-C .m file you want to access the Swift code from.
In this devforums thread, someone mentioned they already filed a bug in Radar. You probably should too.
I've got two Cocoa Touch classes (objective-c). And both #import each other's header.
Class A's header defines an enum, which Class B's header is trying to use. Class B fails to compile due to not recognizing the type.
I think this is a circular dependency issue, but I think #class won't be too much help since the issue is with an enum.
What do you suggest?
Put the enum in it's own header and forward declare the classes with #class where needed in each others headers so A don't need to import B and B don't need to import A but booth import the enum header.
in header files use #class ClassName;
and in .m file use import.
I'm having some error on the following relationship
I have 2 classes, Class A and Class B
inside Class A header, it will #import "B.h"
inside Class B header, it will #import "A.h"
I'm having error during compilation. Anyone know how can I resolve this?
Error looks something like this:
expected specifier-qualifier-list before 'GameUILayer'
Instead of importing the headers in the .h files, use forward declarations. So instead of
#import "ClassA.h"
you use:
#class ClassA
etc
and then you use the import statement within the .m files.
See my earlier answer for the link to the documenation.
You're creating a circular dependency. One class should import the other. They can't both import each other. If you're making interacting classes like that, there should be a hierarchy of dependence. B depends on A, A depends on, at a minimum, the root class NSObject. If you make two classes dependent on each other, the compiler can either yell at you or try to compile it and end up running around in circles. Most compilers are designed to yell at you.
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!
#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.
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
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.
#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
#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
#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
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 .
#class is a forward declaration, a good practice is to put them in the .h instead of #import for avoiding circular #import problem.