我将用一个例子来恰当地说明我的困惑。我无法完全理解这一点。
在Cocoa touch中,我们有UIViewController
及其子类UINavigationController
。现在,UIVC
有一个UINav
类型的ivar,为了解决循环导入问题,他们使用@class UINavigationController
。我假设他们#import "UINavigationController
UIViewController.m
(或某些人)。{/ p>
因此我的困惑是:UIViewController
的子类如何知道UINavigationController
中声明的方法?从UIViewController子类内部可以调用[self.navigationController popViewController]
,但该方法是如何知道的?
我唯一的想法是UINavigationController
必须单独导入到每个子类(可能在前缀?)
有什么想法吗?
答案 0 :(得分:1)
如果这个项目是使用其中一个Xcode模板创建的,那么UIKit中所有类的标题可能都包含在项目的预编译标题中。
答案 1 :(得分:0)
它不是隐藏的导入标题。子类“知道”超类“知道”的一切。这是单一继承设计的优势之一。考虑3个班级;
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
现在创建一个ClassA的子类: ClassC.h
#import <Foundation/Foundation.h>
#import "ClassA.h"
@interface ClassC : ClassA {
}
@end
ClassC.m
#import "ClassC.h"
@implementation ClassC
@end
当您调用ClassC的bclass名称方法时:
#import "ClassC.h"
...
ClassC *c=[[ClassC alloc] init];
NSLog(@"c %@",[[c bClass] name]); //prints "c steve"
在超类实现文件中导入的标头固有的子类。
Edit01:
来自评论:
试试这个:在ClassA.h中定义一个宏, 然后尝试在ClassC.m中使用该宏 (没有导入ClassA.h)。它 不会编译
尽管如此,我认为这是不正确的。以下是编译和运行的实际代码:
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
运行时:
#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
显然,ClassC.m只知道ClassA.h中定义的一个宏,它基于在ClassC.h中导入ClassA.h(它必须作为子类)。
ClassC不会知道ClassA.m中定义的宏,但这是因为实现中定义的宏实际上并不是该类的逻辑部分。 ClassA也不“了解”宏。这样的宏不在类的名称空间中,它只是编译器执行的简单文本替换。 ClassC不知道这样的替换,因为它知道ClassA在其中一种方法中使用了实际的'5'。 ClassC不能固有这样一个宏,因为没有固有的东西。
ClassC知道在ClassA中定义的宏,因为编译器生成的ClassC的真正逻辑头是由导入创建的链中所有头的并集。 ClassC 知道 ClassA知道的一切就像知道Foundation框架知道的一切。
ClassC以与ClassA相同的方式了解ClassB。 @class指令使编译器期待ClassB的定义,并在ClassA.m中找到它。在幕后没有秘密导入大量头文件。那是父母的问题。