ObjectiveC中的循环#import/@类问题
我打算用一个例子来正确说明我的困惑。我无法把头绕在这里。ObjectiveC中的循环#import/@类问题
在Cocoa touch中,我们有UIViewController
及其子类UINavigationController
。现在,UIVC
有一个类型为UINav
的伊娃,并解决他们使用@class UINavigationController
的循环导入问题。我假设他们然后在UIViewController.m
#import "UINavigationController
(或某些)。
我的困惑是:UIViewController
的子类如何知道在UINavigationController
中声明的方法?在UIViewController子类中,可能会调用[self.navigationController popViewController]
,但该方法是如何知道的?
我唯一的想法是UINavigationController
必须分别导入到每个子类中(也许在前缀?)
任何想法?
如果此项目是使用其中一个Xcode模板创建的,那么UIKit中所有类的标题可能都包含在该项目的预编译标题中。
它没有导入标题隐藏。子类“知道”超类“知道”的一切。这是单一继承设计的优势之一。考虑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仅仅基于在ClassC.h中导入ClassA.h(它必须做的子类)来了解ClassA.h中定义的宏。
ClassC将不知道在ClassA.m中定义的宏,但这是因为在实现中定义的宏实际上并不是该类的逻辑部分。 ClassA并不知道这个宏。这样的宏不在类的名称空间中,它只是由编译器执行的简单文本替换。 ClassC不知道这样的替换,它知道ClassA在其方法的某个地方使用了实际的'5'。 ClassC不能固有这样一个宏,因为没有什么是固有的。
ClassC知道ClassA中定义的宏,因为编译器生成的ClassC的真正逻辑头是由导入创建的链中所有头的并集。 ClassC 知道所有ClassA都知道它知道Foundation框架知道的所有内容。
ClassC以类ClassA的方式了解ClassB。 @class指令使编译器期待ClassB的定义,并在ClassA.m中找到它。幕后没有大量头文件的秘密输入。这是父母面临的问题。
“在其超类实现文件中导入的头文件的固有子类[sic]”不,它们不是。子类继承超类的ivars,并且子类中的方法实现可以在其直接超类中调用方法实现。这就是所有的继承。试试这个:在ClassA.h中定义一个宏,然后尝试在ClassC.m中使用该宏(不需要在那里导入ClassA.h)。它不会编译。 – 2009-11-13 23:04:32
想过更多之后,我意识到这是真的。编译器并没有做任何事情,事情正在被导入,它只是隐藏在其他头文件和前缀中。谢谢! – jbrennan 2009-11-13 19:26:27
没有大量导入预编译头文件。 @class指令使编译器向前搜索以查找实现文件中定义的头。你可以通过创建具有循环引用的类来看到这一点。在我的答案中看到我的例子。 – TechZen 2009-11-14 17:15:07
“没有大量导入预编译头文件。” 在Xcode文档中查找“项目头文件”。问题是关于UIKit类;你的例子不适用。 – NSResponder 2009-11-15 19:49:43