I created a category on top on NSObject, because I want ALL of my classes to inherit 2 class methods I wrote:
#interface NSObject (MyCategory)
+ (MyEnum) getXYZ;
+ (void) setXYZ:(MyEnum)myEnum;
#end
Then I imported this category into my PCH file:
#ifdef __OBJC__
#import <Foundation/Foundation.h>
#import <UIKit/UIKit.h>
#import "NSObject+MyCategory.h"
#endif
Then I used the method in one of my classes:
[[self class]getXYZ];
and got this error in runtime:
+[MyClass getXYZ]: unrecognized selector sent to class 0xd04f4
*** Terminating app due to uncaught exception 'NSInvalidArgumentException',
reason: '+[MyClass getXYZ]: unrecognized selector sent to class 0xd04f4'
Did I do something wrong?
Is the category written well?
Are class methods not inherited?
Should I use [super class] instead of [self class]?
Is the PCH file the place to import my category?
Thanks,
Nur
i suppose you have not defined getXYZ method in the implementation file (.m) of category(NSOBject).and for calling the class method of NSObject...use
[NSObject getXYZ];
not
[[self class]getXYZ];
If your category is in an other project that your main project you have to add linker flag "-all_load"
You shouldn't import your Categories in your prefix header (.pch) file. In most cases you only need your category in a few other files, so only import them there. Only import files in your prefix header that are used throughout the whole project.
If you're sure you want to have that category in your prefix header, try setting the Build Setting Precompile Prefix Header to No. Or clean the project. Sometimes Xcode forgets to recompile the prefix header.
Related
In objective-C we can do like this:
a. Importing a file in super class
#import "MyAwesomeClass.h"
#interface MySuperViewController : UIViewController
#end
#implementation MySuperViewController
- (void)viewDidLoad {
[super viewDidLoad];
//MyAwesomeClass allocated, initialized, used
MyAwesomeClass *awesomeClass = [MyAwesomeClass new];
}
#end
b. Using the file imported in superclass, in subclass without re-importing it
#interface MySubViewController : MySuperViewController
#end
#implementation MySubViewController
- (void)viewDidLoad {
[super viewDidLoad];
//No compilation error, since MyAwesomeClass already imported in superclass
MyAwesomeClass *awesomeClass = [MyAwesomeClass new];
}
#end
Trying to do the same thing in swift gives compilation error:
a. importing UIKit in MySuperViewController
import UIKit
class MySuperViewController : UIViewController {
#IBOutlet weak var enterPrice: UITextField!
}
b. Declaring and using an object of UITextField without importing UIKit in MySubViewController
class MySubViewController: MySuperViewController {
// compilation error at below line
#IBOutlet weak var myButton: UIButton!
}
Is there any way we can avoid re-importing UIKit in above scenario? Please suggest.
Short answer:
Yes. It's my understanding that you need to import all the frameworks you need in each Swift file in your project (it is a file-by-file requirement, not class by class. If you define 2 classes in a single file, you only need one import at the top of the file.)
The #import/#include statements in C are preprocessor directives. It is as if the code in the included file is copy/pasted at the location of the include. If you include a header in your superclass's header, the superclass's header now contains the expanded contents. So when you include the superclass header in your subclass, the system framework headers are included as part of the superclass header.
Swift works a little differently.
If you use any objective-C class in your Swift project and import UIKit in that class, you don't actually have to use the import UIKit directive anywhere else in your project!
So basically:
Drag and drop your objective-C .m and/or .h file into your project. Choose copy files if necessary. Make sure all the dependencies are sorted for that file.
(optional) Xcode should prompt you to create a bridging header, if it does, move on to step 4... But if it doesn't, you have to add a header file and call it YourProjectName-Bridging-Header.h.
(optional) If you manually added it, go into Project Settings and search for Swift Compiler. In the General section, there is a place to put the path to the file you just created.
In the bridging header import the objective-c class(es) to your project by doing #import "MyClass.h"
That's it! You are now free to delete your import UIKit statements from every file. It's worth noting that stylistically and for code reuse purposes, it's better to have all of the imports in every file so everyone can see at a glance what dependencies there are, but when you are creating ViewControllers and such I think it's kind of silly to have to import UIKit in every single file. Everyone knows it has a dependency on UIKit and chances are you won't be reusing the UI in another project anyway.
There is a problem, I just installed cocos2d for iPhone.
The first problem was that it wasn't recognizing any header like CCDirectory.h for example.
So I turned on user search paths in the project, but this way I could just import the header and have an object pointer without getting any warning, but methods aren't recognized.
It's hard to explain, so see this code:
Header:
#import <UIKit/UIKit.h>
#import <CCMenuItem.h>
#import <cocos2d.h>
Inside applicationDidFinishLaunching:
CCMenuItem* item; // This does not give a warning, except for the "unused variable"
// But the class is recognized
[CCMenuItem setFontName: #""]; // Warning
The warning is:
Class method '+setFontName:' not found (return type default to 'id')
And it doesn't recognize any other method, just NSObject's methods.
Are you sure the methods you are calling exists in that class? CCMenuItem doesn't contain a static method named setFontName. Try changing CCMenuItem to CCMenuItemFont.
[CCMenuItemFont setFontName: #""];
In my iOS5 app, I have NSObject States class, and trying to init it:
states = [states init];
here is init method in States:
- (id) init
{
if ((self = [super init]))
{
pickedGlasses = 0;
}
return self;
}
But there is error in the line states = [states init];
receiver type "States" for instance message is a forward declaration
What does it mean? What am I doing wrong?
That basically means that you need to import the .h file containing the declaration of States.
However, there is a lot of other stuff wrong with your code.
You're -init'ing an object without +alloc'ing it. That won't work
You're declaring an object as a non-pointer type, that won't work either
You're not calling [super init] in -init.
You've declared the class using #class in the header, but never imported the class.
FWIW, I got this error when I was implementing core data in to an existing project. It turned out I forgot to link CoreData.h to my project. I had already added the CoreData framework to my project but solved the issue by linking to the framework in my pre-compiled header just like Apple's templates do:
#import <Availability.h>
#ifndef __IPHONE_5_0
#warning "This project uses features only available in iOS SDK 5.0 and later."
#endif
#ifdef __OBJC__
#import <UIKit/UIKit.h>
#import <Foundation/Foundation.h>
#import <CoreData/CoreData.h>
#endif
I got this sort of message when I had two files that depended on each other. The tricky thing here is that you'll get a circular reference if you just try to import each other (class A imports class B, class B imports class A) from their header files. So what you would do is instead place a forward (#class A) declaration in one of the classes' (class B's) header file. However, when attempting to use an ivar of class A within the implementation of class B, this very error comes up, merely adding an #import "A.h" in the .m file of class B fixed the problem for me.
I was trying to use #class "Myclass.h".
When I changed it to #import "Myclass.h", it worked fine.
If you are getting this error while trying to use Swift class or method in Objective C: you forgot one of 2 steps Apple defined on this diagram:
Example:
Error shows up in your Test.m file:
Receiver 'MyClass' for class message is a forward declaration
In Obj-C files:
Step 1: check that Test.h has
#class MyClass;
Step 2: find *-Swift.h file name in Build Settings (look for Objective-C Generated Interface Header Name). Name will be something like MyModule-Swift.h
Step 3: check that Test.m imports the above header
#import <MyModule/MyModule-Swift.h>
In Swift file:
Ensure MyClass (or it's base class) inherits NSObject class.
Ensure #objc is before each method you want call from Obj-C.
Also, check Target Membership section (in File Inspector).
You are using
States states;
where as you should use
States *states;
Your init method should be like this
-(id)init {
if( (self = [super init]) ) {
pickedGlasses = 0;
}
return self;
}
Now finally when you are going to create an object for States class you should do it like this.
State *states = [[States alloc] init];
I am not saying this is the best way of doing this. But it may help you understand the very basic use of initializing objects.
Check if you imported the header files of classes that are throwing this error.
Make sure the prototype for your unit method is in the .h file.
Because you're calling the method higher in the file than you're defining it, you get this message. Alternatively, you could rearrange your methods, so that callers are lower in the file than the methods they call.
There are two related error messages that may tell you something is wrong with declarations and/or imports.
The first is the one you are referring to, which can be generated by NOT putting an #import in your .m (or .pch file) while declaring an #class in your .h.
The second you might see, if you had a method in your States class like:
- (void)logout:(NSTimer *)timer
after adding the #import is this:
No visible #interface for "States" declares the selector 'logout:'
If you see this, you need to check and see if you declared your "logout" method (in this instance) in the .h file of the class you're importing or forwarding.
So in your case, you would need a:
- (void)logout:(NSTimer *)timer;
in your States class's .h to make one or both of these related errors disappear.
This question already has answers here:
Closed 11 years ago.
Possible Duplicate:
#class vs. #import
In the .h file you can add a class to be seen(dont know what the correct terminolgy for this is) by using
#import "SomeClass.h"
or instead use
#class SomeClass;
I've tried both methods and they both worked. Whats the difference? Should I be using one of the methods and not the other? What is best practice?
#import includes the content of the header in the source.
Thus, every declaration which is in the imported header is also imported.
#class only declares to the compiler that the given class exists, but does not import the header itself. It is called a forward declaration, as you only declares to the compiler that the class exists before defining it in details (telling which methods it implements and so on)
Consequences:
When using #import in your .m file, if the header is modified, it will trigger the recompilation of the .m file that #import it on next compilation. Instead, if you use #class, your .m does not depend on the header and if the header is modified, the .m file is not recompiled.
Using #class also avoid cross-imports, e.g. if the class A references class B and class B references class A, then you can't #import "A.h" in B.h and #import B.h in A.h in the same time (it would be an "import infinite loop")
Using #class only declare that a class exists and does not tell the compiler which methods the class responds to.
This is why usually the best practice is to forward-declare the class using #class A in the header (.h) files that references class A, just so that the compiler knows that "A" is a known class but doesn't need to know more, and #import "A.h" in the implementation (.m) file so that you can call methods on the objet of class A in your source file.
In addition to avoid import loops, this will also avoid to recompile files if they don't need to, and thus reduce your compile time.
The only exceptions are when the declaration of your class inherits another class, or when it declares that it conforms to a given #protocol (like delegate protocols and so on), because in this particular case, the compiler needs you to #import the whole definition of the parent class or #protocol (to know if your class correctly conforms to this given protocol).
MyClassA.h
// Tells the compiler that "MyClassB" is a class, that we will define later
#class MyClassB; // no need to #import the whole class, we don't need to know the whole definition at this stage
#interface MyClassA : NSObject {
MyClassB* someB; // ok, the compiler knows that MyClassB is a class, that's all it needs to know so far
}
-(void)sayHello;
-(void)makeBTalk;
#end
MyClassB.h
#class MyClassA; // forward declaration here too
// anyway we couldn't #import "MyClassA.h" here AND #import "MyClassB.h" in MyClassA.h as it would create an unsolvable import loop for the compiler
#interface MyClassB : NSObject {
MyClassA* someA; // ok, the compiler knows that MyClassA is a class, that's all it needs to know so far
}
-(void)talk;
-(void)makeABePolite;
#end
MyClassA.m
// import MyClassB so that we know the whole definition of MyClassB, including the methods it declares
#import "MyClassB.h" // thus we here know the "-talk" method of MyClassB and we are able to call it
#implementation MyClassA
-(void)sayHello { NSLog(#"A says Hello"); }
-(void)makeBTalk {
[someB talk];
// we can call the 'talk' method because we #imported the MyClassB header and knows this method exists
}
#end
MyClassB.m
// import MyClassA so that we know the methods it declares and can call them
#import "MyClassA.h"
#implementation MyClassB
-(void)talk { NSLog(#"B is talking"); }
-(void)makeABePolite {
[someA sayHello];
// we can call this because we #import MyClassA
}
#end
PS: Note that if this is a best practice, I know a lot of developers (including myself sometimes ^^) that #import the header it needs in their .h files, instead of only forward-declare it using #class... this is some bad habit — or because these developers doesn't know these subtleties — that you will unfortunately encounter in existing code anyway.
Using #class is called forward declaration. Since usually you don't need to know the specifics of the class in the .h file, this is usually all you need.
Forward declaration prevents you getting into a situation where you import a particular .h file, which says to import another .h file, which says to import the original .h file again, and so on.
The #class forward declaration allows you to have your interfaces behave like interfaces. Meaning: Declare your code.
But this doesn't mean that you can leave out the #import statement. You just moved the responsibility to the implementation to import and make use of it.
Basically it could be seen as an increase in performance as you're not importing any other headers inside your current header.
Important Note: This isn't the case when you're working with delegates.
If you're making use of delegates you always have to have the proper #import statements in place so that the compiler knows which delegate methods are to be implemented by that class.
You might also want to have a look at the following SO question: #class vs. #import
I ended up having these in both of my .h and .m files, this is my first Objective-C program so I'd like some clarification so I can clean thins thing up.
Unless it affects the interface definition you should put it in the .m file.
If you just use a class, use a forward declaration:
#class AClass;
#interface Bob : NSObject {
AClass* a;
}
If you implement something, then import it:
#import "SomeProtocol.h"
#interface Bob : NSObject<SomeProtocol> {
}
These kinds of thing are really "best practice" rather than absolutely essential. Objective C's #import directive means that you can't get errors because you include a file multiple times, so it's not technically a problem, but it will increase compile times.
These are the rules I follow:
If in your header file, you only need to use pointers to classes declared in the header file you are including, then I would just use a class sentence on the header file (.h) and full import on the definition (.m) file.
If you need to use full definition of some stuff on the header file you are including, then the full import goes into the header file.
For the examples, consider files MyClass.m, MyClass.h and MyInclude.h:
Example, scenario #1:
// MyClass.h
#class MyInclude;
#interface MyClass : NSObject {
MyInclude *myIncludeObj;
}
// MyClass.m
#import "MyClass.h"
#import "MyInclude.h"
Exaple, scenario #2:
// MyClass.h
#import "MyInclude.h"
#interface MyClass : NSObject {
MyInclude myIncludeObj; // MyInclude could be a plain C structure
}
// MyClass.m
#import "MyClass.h"
The #import directive is an improvement over the #include directive in that instead of blindly copying the file in place, it will not include it if it has already been included. Therefore you shouldn't experience any problems with #import-ing the same file multiple times.
As far as best practice goes, IMHO it's best to keep the scope as narrow as possible. Therefore I'd suggest putting your #imports in you implementation files (.m). If you require the class definition in your interface file (.h) then you can use the
#class MyClass;
construct to inform the compiler that it will be able to find the relevant header in the implementation file.
Hope this helps.
I have just one rule: Import at the top of the .h file for the superclass and protocols of any classes you declare in the .h file. This is because any file that imports your .h file also needs the declarations for the superclass and protocols. This is also why the default Xcode template has #import <UIKit/UIKit.h> in the .h file rather than the .m file.
For everything else (e.g. types used for ivars and method parameters), use forward-declarations and put the #import in the .m file
Another way to put this is: never use forward declarations for superclasses and protocols.
Best practices is to put #import statements in .m files. If you need access to a class inside the header file, for a property declaration or a function parameter, use a forward declaration, like this:
#class Cocos2DController;
#interface HoppersAppDelegate : NSObject <UIApplicationDelegate> {
Cocos2DController* controller;
}
A forward declaration lets the system know that the class exists, though it's not yet fully defined. With this pattern, you'll keep your headers lean, and guarantee that you're only importing the headers that you want for a specific class, not chaining #imports all through the application.
For a specific problem you might run into: If you include #import statements in a header file, you run the risk of an #import loop if two classes import each other's header files.