2009-11-13 114 views
0

我打算用一个例子来正确说明我的困惑。我无法把头绕在这里。ObjectiveC中的循环#import/@类问题

在Cocoa touch中,我们有UIViewController及其子类UINavigationController。现在,UIVC有一个类型为UINav的伊娃,并解决他们使用@class UINavigationController的循环导入问题。我假设他们然后在UIViewController.m#import "UINavigationController(或某些)。

我的困惑是:UIViewController的子类如何知道在UINavigationController中声明的方法?在UIViewController子类中,可能会调用[self.navigationController popViewController],但该方法是如何知道的?

我唯一的想法是UINavigationController必须分别导入到每个子类中(也许在前缀?)

任何想法?

回答

1

如果此项目是使用其中一个Xcode模板创建的,那么UIKit中所有类的标题可能都包含在该项目的预编译标题中。

+0

想过更多之后,我意识到这是真的。编译器并没有做任何事情,事情正在被导入,它只是隐藏在其他头文件和前缀中。谢谢! – jbrennan 2009-11-13 19:26:27

+0

没有大量导入预编译头文件。 @class指令使编译器向前搜索以查找实现文件中定义的头。你可以通过创建具有循环引用的类来看到这一点。在我的答案中看到我的例子。 – TechZen 2009-11-14 17:15:07

+0

“没有大量导入预编译头文件。” 在Xcode文档中查找“项目头文件”。问题是关于UIKit类;你的例子不适用。 – NSResponder 2009-11-15 19:49:43

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仅仅基于在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中找到它。幕后没有大量头文件的秘密输入。这是父母面临的问题。

+1

“在其超类实现文件中导入的头文件的固有子类[sic]”不,它们不是。子类继承超类的ivars,并且子类中的方法实现可以在其直接超类中调用方法实现。这就是所有的继承。试试这个:在ClassA.h中定义一个宏,然后尝试在ClassC.m中使用该宏(不需要在那里导入ClassA.h)。它不会编译。 – 2009-11-13 23:04:32