Import useless headers - ios

I have a big project which is refactored a lot.
Some classes import unnecessary headers.
#import "someClass1.h"
#import "someClass2.h"
#import "someClass3.h"
f.e:
classA in interface has:
#import "classB.h"
#import "classC.h"
classB in interface has:
#import "classC.h"
So that import classC in classA interface could be removed...
I would like to have my project clean and tidy.
I'm just wondering:
Is there a way to find useless imports quickly?
What is best way for such situations and organizing one interface import of other interfaces?
Does it affect on application performance if you have plenty of useless/duplicated imports?
Any help appreciated

1) No there is no a way you need to check if that import is used in your file (use find function for this);
2) The best way is import UNTIL IS POSSIBLE header in implementation file (.m). If you need to declare that class in your header file (.h) you can use:
#class nameClass
before begin with #interface...etc.
If you already know that instead you need to import that class header file in your header, you can do it. Be careful to avoid #import cycle. In fact suppose to have this situation:
MGCustomViewController.h:
#import "MGViewController.h"
#interface MGCustomViewController : UIViewController
#end
MGViewController.h:
#import "MGCustomViewController.h"
#interface MGViewController : MGCustomViewController
#end
This cause an error at compile time, because you inherit from MGCustomViewController but importing MGCustomViewController.h you are importing again this last header before that the compiler read the #interface MGCustomViewController directive and so will show an error that says something like SUPERCLASS NOT FOUND.
3) No, but effects on the compile time.

Related

Issues with including header files

In my application I have several classes, that cross-over with each other. I need to connect this classes and create properties of them, but some classes are not visible for another, I suppose that main issue here is in including header files.
class MyOperationQueue
#import <Foundation/Foundation.h>
#import "ContentTableView.h"
//#import "CustomTableViewCell.h"
//#import "ObjectForTableCell.h"
#interface MyOperationQueue : NSOperation
#property(assign, nonatomic) BOOL isCancelled;
#property(strong, nonatomic) ContentTableView* tableView; //unknown type name
class ObjectForTableCell
#import <UIKit/UIKit.h>
#import <Foundation/Foundation.h>
#import "MyOperationQueue.h"
#interface ObjectForTableCell : NSObject
#property (strong, nonatomic) MyOperationQueue* currentQueue;//unknown type name
class ContentTableView - here I don't have warnings
#import <UIKit/UIKit.h>
#import "CustomTableViewCell.h"
#import "Protocol.h"
#import "MyOperationQueue.h"
#import "ObjectForTableCell.h"
#import "ImageViewController.h"
#interface ContentTableView : UITableViewController<CellDelegate, NSURLSessionDataDelegate, NSURLSessionDelegate, NSURLSessionTaskDelegate>
Stick a #class MyOperationQueue; above
#interface ObjectForTableCell : NSObject
to make it:
#class MyOperationQueue;
#interface ObjectForTableCell : NSObject
Here is an excerpt from official documentation here:
Referring to Other Classes
An interface file declares a class and, by importing its superclass,
implicitly contains declarations for all inherited classes, from
NSObject on down through its superclass. If the interface mentions
classes not in this hierarchy, it must import them explicitly or
declare them with the #class directive:
#class Rectangle, Circle;
This directive simply informs the
compiler that “Rectangle” and “Circle” are class names. It doesn’t
import their interface files. An interface file mentions class names
when it statically types instance variables, return values, and
arguments. For example, this declaration mentions the NSColor class.
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.
There is also an excellent article (by NSHipster) on various other compiler directives here. I recommend reading it, for this knowledge will likely serve you well in the future.
Sometimes things get messed up when you create circular imports, i.e. MyOperationQueue.h and ContentTableView.h import each other.
A common fix is to remove at least one of those imports and replace them with forward declaration of the classes, i.e. add #class ContentTableView; to MyOperationQueue.h.
You should then import ContentTableView.h in your implementation file MyOperationQueue.m, so that the whole interface is known. This typically also helps reduce compile time.

Subclassing view controller: Forward declaration

I have been following the rule of having:
#MyClassName in the header file of a class
&&
#import "MyClassName" in the implementation
I have now decided to subclass one of my view controllers. If I overwrite a method then I get the following message:
Receiver 'MyClassName' for class message is a forward declaration
To over come this I need to put the #import into the header file which doesn't seem to follow what I thought was best practices.
Can someone explain if I have misunderstood the use of #class?
Or if I am dong things correctly, can someone please explain you need to break best practices and use #import in header file when subclassing?
Many thanks.
Edit:
Thanks for the answers. I think I need to add some more detail to clarify my situation and hopefully my understanding. Here is my header for my base class:
#import <UIKit/UIKit.h>
#import "CorePlot-CocoaTouch.h"
#class Organisation;
#interface LongCallDetailViewController : UIViewController <UITableViewDelegate, UITableViewDataSource>
In my impementation I have
#import "Organisation.h"
My subclass header contains the following:
#import "LongCallDetailViewController.h"
#interface LongCallSubclassViewController : LongCallDetailViewController
#end
If I override a method in the subclass and try to use an Organisation object it gives me the error as I stated above. Therefore I either need to add #import "Organisation.h" into the base classes header or duplicate the #import "Organisation.h" into the subclasses implementation file. Both of which seem wrong to me.
Many thanks.
Within header files, you should be importing other header files for any classes you subclass. You do not need to import header files for classes that are just referenced and not subclassed. For example, a header file might look like:
#import "MySuperClass.h"
#class MyObjectType;
#interface MySubClass : MySuperClass
#property (strong) MyObjectType *value;
#end
Edit:
Based on your new edits, it looks like you are writing your header files correctly. When you only declare #class in a scope, you will not be able to access any of the selectors or properties associated with that class. It is okay to declare using #class in places where you are not intending to use selectors or properties of that class type and just pass around a reference (as in the header I have described above), but as soon as you want to do anything else with the object, you'll need to have imported the header file describing the #interface.
When defining a #class MyObjectType in a header file, it is generally expected that the #import "MyObjectType.h" appears in the associated source file. Header files are intended as a declaration of structure, whereas source files will contain the implementation. For example, the source file associated with the header file I described above might look like:
#import "MySubClass.h"
#import "MyObjectType.h"
#implementation MySubClass
- (void)overriddenFunction {
[self.value anObjectTypeSelector];
}
#end
You shouldn't think about "duplicating" an import statement when they're in two different scopes. When you forward declare #class Organisation in your LongCallDetailViewController header file, you'll have a #import "Organisation.h" in your LongCallDetailViewController source file. If you also need to access this object's properties and selectors in your LongCallSubclassViewController class, you'll need to #import "Organisation.h" in your LongCallSubclassViewController implementation file. Remember: the implementation files do not know about the content of each other; they only know about the contents of the header file.
#import imports definition of class with all public methods and properties.
#import predeclare class, so there is no information about methods and properties
You use #import when:
You subclass a class - other classes importing your class need to know about all methods that class suport.
You implement a protocol - same reason as above.

Forward class as super class

I am trying to do a static library, which uses AFNetworking. I want to distribute the library only with .a and .h files.
However, one of my classes within the library is a subclass of AFHTTPSessionManager. So my previous .h file looked like this:
#import <Foundation/Foundation.h>
#import "AFNetworking.h"
#interface MyClass : AFHTTPSessionManager
+ (MyClass *) sharedInstance;
- (void) doMagic;
#end
When I compiled the library and imported the .a and .h files into a new test project I got an error "Lexical or Preprocessor Issue 'AFNetworking.h' file not found". Thought that the solution would be to use forward class declaration and move the #import "AFNetworking.h" to the .m file like this:
#import <Foundation/Foundation.h>
#class AFHTTPSessionManager;
#interface MyClass : AFHTTPSessionManager
+ (MyClass *) sharedInstance;
- (void) doMagic;
#end
Unfortunately, this approach throws an error "Attempting to use forward class 'AFHTTPSessionManager' as superclass of 'MyClass'".
As far as I understand forward class declaration you use it just to say "hey compiler classXXX exists, but you cannot see its methods and properties". Therefore, I am not sure if that's the solution to my problem.
Any suggestion how to subclass from a class but not import it?
You can't subclass a class whose header is unavailable. The best you can do is to make your subclass of AFHTTPSessionManager private and instead expose a class (a subclass of NSObject, say) which acts as a facade, forwarding messages to your private class.
You can also use a protocol as the interface for your class and just expose a method which returns an id<MyClassProtocol>. Something like:
#protocol MyClassProtocol
- (void) doMagic;
#end
id<MyClassProtocol> GetSharedInstance();
And then have a class like this which is not exposed from your library:
#interface MyClass<MyClassProtocol>: AFHTTPSessionManager
// ...
#end
Which you can instantiate and return from GetSharedInstance.
You should be importing the class here, not forward declaring it. Any class that uses your subclass should also have access to all of the public methods and variables part of the superclass without having to then also import it manually. The first error you mentioned shows that either your class is not included in the target or perhaps you are importing it wrong.
How are you including AFNetworking. Are you using cocoapods?
If so, try importing it this way.
#import <AFNetworking.h>
Otherwise, make sure that AFNetworking.h is actually part of your build target using the File Inspector Panel on the right side of Xcode.

Swift compiling bug "Unknown type name" and "Expected a type"

I'm running into an issue where my Swift code compiles fine but then the generated -Swift.h file has an error in it...
Here is an example of what I'm doing:
class MyScene : CCLayer {
var ctrl : CCControlSlider?
}
This compiles just fine in the swift code and I can see the methods on the ctrl object just fine as well. I have the following in my bridge header:
#import "cocos2d.h"
#import "CCControlSlider.h"
This works perfectly fine in other classes that use other libraries which work correctly. Also note that I can use this CCControlSlider class in my objective-c classes with no issues at all as well.
Here is what happens on the generated -Swift.h file:
SWIFT_CLASS("_TtC15MyProject10MyScene")
#interface MyScene : CCLayer
#property (nonatomic) CCControlSlider * ctrl;
#end
The property has the error "Unknown type name "CCControlSlider" and if it's used in a method then it gives the error "Expected a type".
This works just fine using other classes but for some reason this one class gives this compiler error only in the generated header file and only when used from Swift.
I guess what I'm wondering is, am I doing something wrong or is this just a bug??
While incorporating a set of Objective C files into my mostly Swift-based project I suddenly started getting a lot of these errors on them. Then I realized though the file had:
#import <Foundation/Foundation.h>
It did not have:
#import <UIKit/UIKit.h>
and once I added that line the errors started resolving. Cleaning afterwards always helps. Good luck
NOTE: With newer versions of Swift imports are much easier to type and are done like so:
import UIKit
If you don't want to worry about the order of imports everywhere you import your ProjectName-Swift.h file, try this:
Create a file named ProjectName-Swift-Fixed.h with the following contents
// ProjectName-Swift-Fixed.h
#class CCControlSlider;
// (Add other imports or forward declarations here)
#import "ProjectName-Swift.h"
Second, throughout the rest of your codebase, replace #import "ProjectName-Swift.h" with #import "ProjectName-Swift-Fixed.h"
This approach has two benefits over copying and pasting a list of #import statements above each place you use Swift classes in Objective-C code:
You won't have to worry about the order of imports, except in the ProjectName-Swift-Fixed.h file
When you add new Objective-C classes to your Swift code, you won't have to add new #import statements in every Objective-C file that uses Swift code
The answer given here is the simplest approach: https://stackoverflow.com/a/24216718/341994
Basically, somewhere in your Objective-C code you are importing the automatically generated -Swift.h header. In that same code, before that #import line, insert #import "CCControlSlider.h". The order of these two #import statements is crucial!
The fact that this Objective-C class may not need CCControlSlider is irrelevant (though if it does, that's a bonus). The important thing is the order. We want to expose the namespace to CCControlSlider before exposing the namespace to the automatically generated -Swift.h header.
OC code has a global call # import "projectName - swift. H", and "the projectName - Bridging - Header. H" and calls the OC code.Is equivalent to the parent class call subclasses, subclasses and calls the superclass.To make the "projectName - Bridging - Header. H" calls the oc class don't call # import "projectName - swift. H.

Cocos2D/iOS: usage of "#class Component" tag

I am using Cocos2d 2.x and iOS 5.0.
Could anyone share with me a good tutorial or explanation on the usage of "#class Component" tag?
Is there any design/patter that refers to it or does it do something more specific to the code?
I haven't found much on my google search.
#class just tells the compiler that the name following it is the name of an Objective-C class. It's used in .h files when it's necessary to define a symbol of that type but where importing the entire definition would either be overkill or cause an actual problem. (For example, two classes that each refer to the other.)
The way it works is that normally if you reference a class in an interface, you have to #import that class' header file:
#import "OtherClass.h"
#interface MyClass : NSObject
{
OtherClass* someOtherClass;
}
#end
The #class statement allows you to skip importing the header:
#class OtherClass;
#interface MyClass : NSObject
{
OtherClass* someOtherClass;
}
#end
You still have to #import "OtherClass.h" in the implementation file if you use #class.
// Still need to import, but now any class importing MyClass.h
// does not automatically know about OtherClass as well.
#import "OtherClass.h"
#implementation MyClass
…
#end
When you #import "MyClass.h" somewhere else in a third class, that third class does not automatically include the header of the OtherClass class if you have used #class OtherClass; in the MyClass header. Therefore the third class has no knowledge of OtherClass unless it expressly imports the OtherClass.h header. This is helpful when writing a public API that should hide its implementation details (ie OtherClass) from the developer.
Forward declaration is considered good practice (if only because it has no downsides other than a slightly altered workflow) and is preferable to importing the class' header in another header file. This certainly helps prevent cyclic imports as mentioned by Phillip.
I don't know about Xcode but in Visual Studio (C++) class forwarding was also instrumental to speed up compilation in larger projects with hundreds of classes. That was because the VS C++ compiler spent quite some time resolving header dependencies

Resources