I'm going to use an example to properly illustrate my confusion. I can't quite wrap my head around this.
In Cocoa touch, we have UIViewController
and its subclass, UINavigationController
. Now, UIVC
has an ivar of type UINav
, and to get around the circular import problem they use @class UINavigationController
. I am assuming they then #import "UINavigationController
in UIViewController.m
(or somesuch).
My confusion is thus: How do subclasses of UIViewController
then know about the methods declared in UINavigationController
? From inside a UIViewController subclass one might 开发者_运维百科call [self.navigationController popViewController]
, but how is that method known?
The only idea I have is UINavigationController
must be separately imported to every subclass (perhaps in the prefix?)
Any ideas?
If this project was created with one of the Xcode templates, then the headers for all the classes in the UIKit are probably being included from the pre-compiled header of the project.
It's not imported headers hidden away. Subclass "know" everything the super class "knows". This is one of the strengths of a single inheritance design. Consider 3 classes;
ClassA.h
#import <Foundation/Foundation.h>
@class ClassB;
@interface ClassA : NSObject {
ClassB *bClass;
}
@property(nonatomic, retain) ClassB *bClass;
@end
ClassA.m
#import "ClassA.h"
#import "ClassB.h"
@implementation ClassA
@synthesize bClass;
-(ClassB *) bClass{
return [[ClassB alloc] init];
}
@end
ClassB:
#import <Foundation/Foundation.h>
@class ClassA;
@interface ClassB : NSObject {
ClassA *aClass;
NSString *name;
}
@property(nonatomic, retain) ClassA *aClass;
@property(nonatomic, retain) NSString *name;
@end
ClassB.m
#import "ClassB.h"
#import "ClassA.h"
@implementation ClassB
@synthesize aClass;
@synthesize name;
-(NSString *) name { return @"steve";}
@end
Now create a subclass of ClassA: ClassC.h
#import <Foundation/Foundation.h>
#import "ClassA.h"
@interface ClassC : ClassA {
}
@end
ClassC.m
#import "ClassC.h"
@implementation ClassC
@end
When you call ClassC's bclass's name method:
#import "ClassC.h"
...
ClassC *c=[[ClassC alloc] init];
NSLog(@"c %@",[[c bClass] name]); //prints "c steve"
Subclasses inherent the headers imported in their super classes implementation file.
Edit01:
From the comments:
Try this: Define a macro in ClassA.h, then try to use that macro in ClassC.m (without importing ClassA.h there). It won't compile
In all due respect, I think this is incorrect. The below is actual code that compiles and runs:
ClassA.h
#import <Foundation/Foundation.h>
#define aMacro 5
@class ClassB;
@interface ClassA : NSObject {
ClassB *bClass;
}
@property(nonatomic, retain) ClassB *bClass;
@end
ClassC.h
#import <Foundation/Foundation.h>
#import "ClassA.h"
@interface ClassC : ClassA {
}
-(void) logMacro;
@end
ClassC.m
#import "ClassC.h"
@implementation ClassC
-(void) logMacro{
NSLog(@"aMacro=%d",aMacro);
}//-------------------------------------(void) logMacro------------------------------------
@end
When run:
#import "ClassC.h" //the only header imported of the three classes ./////////
...
ClassC *c=[[ClassC alloc] init];
NSLog(@"c %@",[[c bClass] name]);
[c logMacro]; //prints 5
Clearly, ClassC.m knows about a macro defined in ClassA.h based solely on importing ClassA.h in ClassC.h (which as a subclass it must do).
ClassC won't know about a macro defined in ClassA.m but that is because a macro defined in an implementation isn't actually a logical part of the class. ClassA doesn't 'know' about the macro either. Such a macro is not in the class's name space, it's just a simple text substitution performed by the compiler. ClassC doesn't know about such substitutions anymore than it knows that ClassA used an actual '5' somewhere in one of its methods. ClassC can't inherent such a macro because there is nothing to inherent.
ClassC knows about macros defined in ClassA because the true logical header for ClassC that the compiler generates is the union of all the headers in the chain created by the imports. ClassC knows everything ClassA knows just like it knows everything that the Foundation framework knows.
ClassC knows about ClassB the same way that ClassA does. The @class directive causes the compiler to look forward for the definition of ClassB and it finds it in the ClassA.m. There is no secret importing of masses of header files behind the scenes. That was the question poised in the parent.
精彩评论