#import不能防止循环呼叫?

时间:2011-09-29 19:15:06

标签: objective-c import header include

我有两个类ClassA和Class B(它们是viewControllers) A类是classB的代表 ClassA“laucnhes”和ClassB的实例。
classA上的ClassB调用方法。

让我们说:

#import "ClassB.h"

@interface ClassA : NSObject {
    ClassB* subController;
}

- (void) doThis;

-------------------------------

#import "ClassA.h"

@interface ClassB : NSObject {
    ClassA* delegate;
}

-------------------------------

@implementation ClassB

- (void) someMethod {
   AnObject* myObj = [self.delegate.arr objectAtIndex:8];
   [self.delegate doThis];
}

这样做,A必须导入B,B必须导入A.

如果B不导入A(仅使用@class A),则来自A的已使用属性存在编译错误。
如果B导入A,则ClassA* delegate行上存在编译错误。

为什么我有这些编译错误? #import不会再次保护递归调用吗?

我不需要解决方案来解决这个问题,我知道如何解决这个问题。
 但我想知道为什么我的#import会导致这些问题。这些不是#includes ......

4 个答案:

答案 0 :(得分:6)

在.h文件中更喜欢@class到#import。然后可以在.m实现文件中导入两者。

// ClassA.h -------------------------------
@class ClassB;
@interface ClassA : NSObject {
    ClassB* subController;
}

- (void) doThis;

// ClassB.h -------------------------------
@class ClassA;
@interface ClassB : NSObject {
    ClassA* delegate;
}

// ClassB.m -------------------------------
#import "ClassA.h"
#import "ClassB.h"

@implementation ClassB

- (void) someMethod {
   AnObject* myObj = [self.delegate.arr objectAtIndex:8];
   [self.delegate doThis];
}

使用@class语句而不是#import也可以减少依赖关系并使其余的更清晰。它还可以加快编译时间。

答案 1 :(得分:5)

  

为什么我有这些编译错误? #import不会再次保护递归调用吗?

#import可以防止重复将相同的标头导入同一个模块,无论是否通过循环包含/导入。它通过不让你这样做来防止这种情况:只有标题的第一个#import起作用;

。忽略相同标题的后续#import

在循环#include情况下,预处理器会绕圈数次,然后在编译之前使构建失败。使用#import可以防止预处理器被楔入并让预处理器成功,但循环 - #import代码仍然是狡猾的,通常不会编译。

所以,根据你的具体情况。

对于您在问题中显示的代码,@class将在其中一个或两个标题中起作用,实际上您应该在两者中使用它。您还需要{。1}}两个.m文件中的两个标头。

  

如果B不导入A(仅使用@class A),则A中使用的属性存在编译错误。

如果你的意思是“在我使用#import类型的属性的每个点都有编译错误”,那么是:你不能与那个对象交谈,因为你没有导入它的接口,所以编译器不知道您可以向ClassA *实例发送哪些消息。这就是您需要导入其界面的原因。

  

如果B导入A,则ClassA *委托线上存在编译错误。

如果两个标题相互导入,那么你有:

ClassA

如果没有一个接口在另一个接口之前没有其他接口,那么这种方法是行不通的。这就是你遇到的圈子 - ClassA.m: ClassA.h ClassB.h ClassA.h (ignored because this was already imported by ClassA.m) ClassB.m: ClassB.h ClassA.h ClassB.h (ignored because this was already imported by ClassB.m) 存在的圈子。 #import允许圆圈,从而被楔入:

#include

因此ClassA.m: ClassA.h ClassB.h ClassA.h ClassB.h ClassA.h ClassB.h ClassA.h ClassB.h ClassA.h ClassB.h ClassA.h ClassB.h (fails at some point)

因此您无法从另一个导入每个标头。因此#import

但您仍需要从每个模块导入每个标头。也就是说,事实上,您需要做的就是:在每个标头中使用@class,并在每个模块中使用@class(在两个标头上)。

答案 2 :(得分:1)

通过声明

可以避免此编译投诉
@class ClassB;
.h文件中的

。然后可以将ClassB.h包含在.m文件中。

所以你是对的。与都市神话相反,#import的工作方式与#includes非常相似,因为编译器必须检查文件。

请参阅this(重复?)问题,了解您的哲学问题。

答案 3 :(得分:0)

我认为你会发现#import只有在成功包含一次后才能防止多次包含,可以这么说。

即,在您的情况下,它还没有成功导入classa.h,然后再要求它再次导入它,所以它会这样做。