Declaring a subclass in ObjC fails - objective-c

Here's what I'm trying to do:
I want to put away some methods into separate .h and .m files for a better overview of my code.
So basically I have the myViewController which I want to extend with the method myReactionOnAnimationDidEnd: as a category.
So I declared in "myCustomClasses.h" the following to extend it with my desired method:
#import "myViewController.h"
#interface myViewController (myReactionOnAnimationDidEnd)
- (void)myReactionOnAnimationDidEnd:(NSNotification *)aNotification;
#end
The implementation in "myCustomClasses.m" is:
#import "myCustomClasses.h"
#import "myViewController.h"
#implementation myViewController (myReactionOnAnimationDidEnd)
- (void)myReactionOnAnimationDidEnd:(NSNotification *)aNotification {
self.myLabel1.text = #"Test";
}
#end
The Compiler throws a build failed error "Cannot find interface declaration for 'myViewController'"
So here's my questions:
The first weird thing is, that everything works fine if I do exactly the same for UIViewController instead of myViewController. But since myViewController is a subclass of UIViewController, why shouldn't it work for myViewController as well(#interface iSnahViewController : UIViewController)?
The other weird thing is that the #implementation in "myCustomClasses.m" works just fine if I skip on the #declaration completely. Now how can that be??
Thank you guys!
Any help much appreciated!!
Hans
Now, the funny thing is, that this very same building error comes up even if I create the category with the New File -> ObjC - Category Template. It basically creates the following two files:
in the header file:
#import "myViewController.h"
#interface myViewController (myCategories) //<-- "Cannot find interface declaration for 'myViewController'"
#end
and with the .m file
#import "myViewController+myCategories.h"
#implementation myViewController (myCategories)
#end
And that's already enough to bring up the error from above.

myCustomClasses.m should probably include myCustomClasses.h and not myViewController.h, so the compiler sees the category declaration. Since myCustomClasses.h already includes myViewController.h, the compiler should have all necessary declarations.

I finally got it working!
As the building error occured, I was importing the Category-.h File into the primery Class's .h file:
#import "myViewController+myCategories.h" //<-- in the "myViewController.h"
which lead to the building error from above. This seems to be wrong! So don't do that.
I still don't fully understand how the "myViewController" Class gets to know about it's categories without even having their .h files imported, but as this appears to be a working way of how this is done, I wanted to share with you.
Thanks everybody for helping!!

Related

Objective C - 2 .m files for one .h file?

My question is, that I would know how to use 2 .m files for one objectclass also for one header (.h)
I have a big method with 20000+ lines and I would, that this method stand alone in a .m file and the other methods in the other .m file. I have done it, but I get errors, that the methods aren not in the one .m file. I get a link error, but i can remove the link error if i delete the second .m file.
Is it possible to create 2 .m files for one header ?
If yes pleas tell me how?
I have a big method with 20000+ lines
Okay, that's your problem right there. That's what you need to fix. Splitting things up into two implementation files is a distraction. This is your main problem. There's virtually no circumstances where this is not a terrible way of doing things.
Methods should be a few dozen lines long at most. If you find yourself writing a method that is longer than that, you need to break the functionality down into smaller pieces. Create smaller methods to do part of the job, then call those methods from your original method.
Classes should not be this size. If you are creating a file with more than a couple of thousand lines of code in, it's a huge warning sign that one class is responsible for too much functionality. You should break the functionality down into several classes, each of which is responsible for one key piece of functionality.
I get a link error
If you post a sentence like this to Stack Overflow, it should be accompanied by the actual error you get.
You can make the excessively long method a category of the class:
MyClass.h:
#interface MyClass
#property ...
-(void) method;
...
#end
#interface MyClass (BigMethod)
-(void) bigMethod;
#end
MyClass.m:
#implementation MyClass
-(void) method
{
...
}
...
#end
BigMethod.m
#implementation MyClass (BigMethod)
-(void) bigMethod
{
...
}
#end
However, a 20k line method is absurd. You should really refactor it.
You have several approaches:
you could split your methods into 2 different categories:
//-- MyClass1.m
#implementation MyClass (part1)
#end
//-- MyClass2.m
#implementation MyClass (part2)
#end
I defined 2 categories for symmetry reason; of course you also need a "base" #implementation of your class (i.e., without the category specifier); you can choose whether you define a "base" and and extension category, or "base" and two categories, etc...
or you might try including the second .m file inside of the first one:
//-- MyClass1.m
#implementation MyClass
<first part>
#include "MyClass2.m"
#end
Both should work.
Let alone the possibility of refactoring your class, which would be the best option.

Why won't Xcode recognize a typedef from a header that's being properly imported?

I used to have a class called Constants. In it was this typedef:
typedef enum visible_thing {
BACKGROUND,
BACKGROUND_COLOR,
MAIN_WINDOW
} VISIBLE_THING;
And my, was life rosy! I was importing 'Constants.h` wherever I needed to access this type, and it all worked.
Then I decided to nuke the Constants class. I took the typedef and I put it in another class, for clarity let's call it OtherClass. I went through and changed all the imports of Constants.h to imports of OtherClass.h That's all I did, I didn't touch any other code. And now the whole thing's broke!
Methods that worked perfectly with Constants now give me this error: Parse Issue - Expected a type. What the heck? I sure hope someone has some leads on this!
Update: frustratingly, this is one of those problems that just seemed to go away on its own without explanation. I answered my own question, below, with a workaround I'd found that entailed #import-ing the same header multiple times in one file. But today I removed the extra #import, and everything still worked. Arg. Computers!
I got the same "Expected a type", and it turns out that it was caused by an imports loop. I reproduced it with the following simple example:
A.h:
#import "B.h"
typedef enum {
SomeEnumA
} SomeEnum;
#interface A : NSObject
#end
B.h:
#import "A.h"
#interface B : NSObject
- (void) func:(SomeEnum)arg;
#end
The compiler complains about SomeEnum unknown in B.h - while compiling A.m (which just imports A.h). This happens because A.h imports B.h which imports A.h. The imports loop doesn't occur, so B.h in this case does not include the A.h code where the type is defined.
The issue can be easily solved by moving the definition of the enum to a separate SomeEnum.h .
I would probably try to figure out what's going on, because what ever is causing this to happen might cause other mysterious bugs in the future, and by that point you might have forgotten about this, which could make it more difficult to track down the cause of the future bugs.
I would try to isolate the problem. A few things that you could try:
progressively commenting out code in the InnerClass interface to see if you can get the problem to go away.
manually adding a typedef at the top of your file with a different type name (and editing the rest of your code appropriately) to see if the problem is still there.
posting your .h file and OtherClass.h file to see if anyone else can spot the problem
David H's suggestion of creating a demo project to see if you can reproduce the problem
I think it depends on what your project is, if it's just something small and fast that you want to get working, it probably doesn't matter, but if it's going to be a larger project and you forsee your code base expanding, or if it's something that other coders are going to be working on as well, I would try to understand what's happening here.
The class that was generating the errors had two other class definitions inside it, helper classes that were only used internally. Apparently that was the root of the problem.
What I didn't know was that if you do that, if there is more than one class in a file, you may need to import the same header multiple times.
Here's what I did to fix it. I changed this:
#import "OtherClass.h"
#interface InnerClass
// uses typedef from OtherClass
#end
#interface MainClass
// uses typedef from OtherClass
#end
To this:
#import "OtherClass.h"
#interface InnerClass
// uses typedef from OtherClass
#end
#import "OtherClass.h" //<--without this, MainClass won't recognize the typedef
#interface MainClass
// uses typedef from OtherClass
#end
Which seems clunky and like I may be doing something else wrong, but at least it fixed the issue at hand. Any follow-up comments will be appreciated.
I just stumbled into this one while trying to create a Framework. Xcode didn't like the typedef to be defined above the interface. Not sure why this is, but it fixed it.
So I changed mine from:
typedef enum {
MyOption1, // option 1.
MyOption2, // option 2.
}MyOption;
#interface MyClass : NSObject
#property (strong, nonatomic) NSString *myString;
#end
to:
#interface MyClass : NSObject
typedef enum {
MyOption1, // option 1.
MyOption2, // option 2.
}MyOption;
#property (strong, nonatomic) NSString *myString;
#end

how to access a newly created class in objective c

I get the feeling that this is a very stupid question, but I cannot find an answer anywhere. I've created a new class in an XCode project called "Word", with its own .h and .m files, which inherits from NSString, and has its own declared instance variable, method, etc. How do I access it within the viewcontroller.h and .m files? I though it would just show up in the little suggestion box in XCode, like the pre-made classe, but it doesn't. How do I use my new class?
#import "Word.h"
I will note that subclassing NSString is extremely uncommon and almost never what you mean to do. You probably meant to have Word have an NSString property.
in your .h, at the top type #import " then start typing Word.h. It should autocomplete if the .h and .m files are in your project correctly.
You just need to add the following to your ViewController.h
#import "Word.h"

Strange Delegate Protocol Declaration error?

So in a header file I have the following code:
#import <AudioToolbox/AudioToolbox.h>
#interface alertController:UIViewController <AVAudioPlayerDelegate>
{
AVAudioPlayer *player;
}
I have both the framework linked and It works just fine in another file within the same project, but I am getting the error that it cannot find the protocol declaration for "AVAudioPlayerDelegate", nor does it recognize the line AVAudioPlayer * audioPlayer because it is an unknown type name. Any ideas why this isn't working despite my import statement, including the framework, and the fact that it's working fine in another file?
AVAudioPlayer (and its delegate) come from AVFoundation, not AudioToolbox. Your other project probably imports <AVFoundation/AVFoundation.h> either through a separate included header file or through your PCH. You should replace that #import with
#import <AVFoundation/AVFoundation.h>

what does #class do in iOS 4 development?

Is there any difference in doing
#class MyViewController;
rather than doing the normal import of the .h into the appdelegate.h
#import "MyViewController.h"
I've seen some example recently that use the #class way and wondered if there any differences.
thanks.
There is a big difference.
#class MyViewController;
Is a forward declaration for the object MyViewController. It is used when you just need to tell the compiler about an object type but have no need to include the header file.
If however you need to create an object of this type and invoke methods on it, you will need to:
#import "MyViewController.h"
But normally this is done in the .m file.
An additional use of forward declarations is when you define a #protocol in the same header file as an object that uses it.
#protocol MyProtocolDelegate; //forward declaration
#interface MyObject {
id<MyProtocolDelegate> delegate;
...
}
...
#end
#protocol MyProtocolDelegate
... //protocol definition
#end
In the above example the compiler needs to know that the #protocol MyProtocolDelegate is valid before it can compile the MyObject object.
Simply moving the protocol definition above MyObject definition would also work.
#class allows you to declare that a symbol is an Objective-c class name without the need to #import the header file that defines the class.
You would use this where you only need the class name defined for the purposes of declaring a pointer to the class or a method parameter of the class, and you do not need to access any methods, fields, or properties in the class.
It saves a minuscule amount of compile time vs the #import, and it sometimes helps avoid messy include circularity issues.
[And, as rjstelling points out, it's sometimes useful where you have interleaved declarations and you need to "forward declare" something.]