Purpose of #class in Objective-C - objective-c

I have the following code
#import <UIKit/UIKit.h>
#import "SecondLevelViewController.h"
#class DisclosureButtonController;
#interface DisclosureButtonController : SecondLevelViewController {
NSArray *list;
DisclosureButtonController *childController;
}
#property (nonatomic, retain) NSArray *list;
#end
I can`t get what
#class DisclosureButtonController;
means.
Can anyone explain to me ?

It simply tells the compiler that DisclosureButtonController is a Class that is defined elsewhere.
If you remove it you should get an error at DisclosureButtonController *childController; because the compiler doesn't know what you want him to do at this line.
From Apple Doc Defining a class
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.
EDIT: I just saw that the #class directive is superfluous there, because you are declaring this class at the next line. Maybe there was a #protocol that used the class in between #class and #interface. But in your special case you could remove it without problems. It's redundant.

Related

Using extern #class in order to add a category?

Is there a way to "promise that a class exists elsewhere" (i.e. similar to the extern keyword) and therefore avoid having to use #import statements?
Here is an example of what I am trying to do:
extern #class MyClass;
#interface Foo : NSObject
#property (nonatomic) MyClass *abc;
#end
Where MyClass definitely exists and is used throughout my program, but at the time I create this file, I don't know the name of the file where MyClass is defined.
Update: It seems like the error is related to the fact that this is a category. Updated code follows:
#class MyClass;
#interface MyClass (Extensions)
- (void)foo;
#end
Gives the following error:
Cannot define category for undefined class 'MyClass'.
You can "forward declare" a class by simply doing:
#class MyClass;
When you actually go to use the class though, you will still need to import the header.
However, you must use an import when subclassing or adding a category for the class. The compiler must be able to see the real class in order to modify or extend it.
Your only option to "extend" a class that you can't import directly into a file would be to modify the class at runtime using the objective-c runtime library. You could create another class and then add the methods from that class to the real class at runtime.
Basically you would use NSClassFromString to get the class and then use class_addMethod to add those methods to the real class.
This is almost certainly overkill for anything you would want to do though.
Yes, that's exactly what the #class directive is for (without the extern part).

Objective-C #interface and #implementation clarification

I'm still fairly new to Objective-C but I'd love to learn more about how it should be done.
I'm building a simple cheat sheet that I'd like to print and put on my office wall as a reminder.
Here's what I have so far:
// Headers (.h)
// Shows what's available to other classes
#interface ExampleViewController : UIViewController
// Declare public methods, ivars &
// properties that are synthesized.
#end
// Implementation (.m)
// Defines the content of the class
#interface ExampleViewController ()
// Class extension allowing to declare
// private methods, ivars & properties that are synthesized.
#end
#implementation ExampleViewController
// Private Properties
// Method definitions
#end
One thing I don't understand is why have both #interface and #implementation inside the implementation .m file?
I get that we can declare private stuff but why not simply throw them in #implementation like:
#implementation ExampleViewController
UIView *view; // private property
- (void)...more code
#end
#1 - Why should I ever use #interface from within my implementation .m file?
#2 - For header .h, why should I ever use #class more than #import?
#import actually gets the whole definition and #class tells the compiler that the symbol is a class. So I just don't see why I should ever use #class?
#3 - Otherwise, is there anything I should be adding somewhere in my .h or .m cheat sheet?
That's not a problem-related question but a more wiki-esque question so we everybody can look it up and completely and quickly understand those concepts as they are very hard to grasp for any newcomer.
Why should I ever use #interface from within my implementation .m file?
Because it's better to clearly separate public and private parts of the class.
For header .h, why should I ever use #class more than #import?
When forward-declaring classes for use in protocols. Like this:
#class Foo;
#protocol FooDelegate
// this wouldn't compile without a forward declaration of `Foo'
- (void)fooDidFinishAction:(Foo *)f;
#end
Otherwise, is there anything I should be adding somewhere in my .h or .m cheat sheet?
That's way too general to be answered in one post.
1 - Why should I ever use #interface from within my implementation .m file?
When you do not intend to expose that interface to any other component. That's certainly the case for private class extensions but may also apply for something like a test which doesn't need a .h file at all because while it does define a class it does not need to expose an interface for any other component to use.
2 - For header .h, why should I ever use #class more than #import?
Invert your question; why should I ever use #import rather than #class?
#class informs the compiler that a class definition of that name will exist to be linked but says nothing about it's interface.
#import makes the class' interface available to you.
A forward declaration requires less work and can allow for faster builds. It is also not always possible to #import a class at all times (as in circular references like #H2CO3's protocol example). If all you need to know is that a class exists then just use the forward declaration. When you actually need to interact with its specific interface (usually in your class' implementation) then you need to #import.
3 - Otherwise, is there anything I should be adding somewhere in my .h or .m cheat sheet?
Unless you intend to actually expose ivars as a public interface (almost certainly not the case) leave them out of your .h and expose only properties instead.
Keep your public interface as simple as possible. Try not to reveal implementation details. However keep it informative enough that users of the class can verify its behavior using that public interface. (I find test driving the design of the class using only it's public interface a good tool for striking this balance.)
Imports and forward declarations expose dependencies. Keep them to the minimum you actually need so that you can understand what the class in question actually depends on.
Delegate protocols and block types are a common part of a class' interface but not part of the #interface. Include them in the .h if they are needed by other classes (e.g. to register callbacks).

what was it help for compiler when used #class-#interface pair?

#class GSValue;
#interface GSValue : NSObject // Help the compiler
#end
#class GSNonretainedObjectValue;
#interface GSNonretainedObjectValue : NSObject // Help the compiler
#end
the above code from NSValue.m . i google and giving me some info, it indicate that #class(not accompanying with #interface) used for class forward declaration between two classes,but only declared as a pointer of the class. my question is why "#class GSValue;" immediately followed by "#interface GSValue:NSObject",what's the meaning?
I'm not quite sure, but i think in this case it's forward declaration + declaration, that GSValueand other classes are subclasses of NSObject. So, compiler won't give a warning when you write [GSValue class]. It's not actually "help", it's just to get rid of warnings.
Though, if this is the case then I don't know why they use forward declaration with #interface, cause it works just the same without #class directive.
I see it that way.
They used forward declaration in the first place. Then they noticed that compiler gives warnings Receiver 'GSValue' is a forward class and corresponding #interface may not exist, so they added #interface sections, but forgot or didn't bother to delete former #class directives.

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

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.]