【问题标题】:Objective-C #import loopObjective-C #import 循环
【发布时间】:2009-08-03 18:34:19
【问题描述】:

我有以下代码:

#import <Foundation/Foundation.h>
#import "ServerRequest.h" // works even though this line is included
#import "ServerResponseRecord.h"

@protocol ServerRequestDelegate<NSObject>

-(void)request:(id)request gotResponseRecord:(ServerResponseRecord*)response;
-(void)request:(id)request gotError:(NSError*)error;

@end

它编译并运行良好。但是,如果我将方法声明替换为:

-(void)request:(ServerRequest*)request gotResponseRecord:(ServerResponseRecord*)response;
-(void)request:(ServerRequest*)request gotError:(NSError*)error;

我在 'ServerRequest' 之前收到意外的语法错误“错误:预期的 ')'”。我认为这可能是一个问题的唯一原因是 ServerRequestDelegate.h 和 ServerRequest.h #import 彼此。但是,我不明白为什么代码与带有(id)请求的#import 行一起使用。我也不明白为什么是语法错误。

有人可以提供一个很好的解释吗?

【问题讨论】:

标签: objective-c xcode gcc compiler-construction import


【解决方案1】:

您已经暗示了解释:#import 循环。

我要做的第一件事是删除 #include 并在 @protocol 定义上方添加以下行:

@class ServerRequest;

这是一个前向类声明,可以帮助打破导入循环。查看this SO question 了解更多详情。苹果在this guide也有简要说明。

基本上,#import'ing 一个文件会导致编译器将该文件的整个文本带入相关文件中,尽管#import#include“更聪明”,但这并不意味着你'重新免受导入错误的影响。 @class 声明是一种告诉编译器类存在而不导入头文件的方法。当你只需要知道类名,而不关心它提供的方法时使用它是合适的。通常,您希望在 .h 文件中使用 @class,在 .m 文件中使用 #import,您实际上是在与类交互的地方。

【讨论】:

  • 是的,在任何级别上移动到标头中的 @class 声明都更好,但除非问题是没有适当前向声明的循环依赖,否则标头中可能仍然存在潜在错误。跨度>
  • 是的,但是如果他使用id 作为类型,它可以与包含的标头一起使用,但在静态键入为`ServerRequest*` 时却不行,这表明标头可能没问题,并且编译器只有在开始尝试找出有关 ServerRequest 类的信息时才会出现问题。
【解决方案2】:

#import“循环”不是问题。 #import 与 #include 相同,只是它跟踪文件并确保预处理器仅在第一次读取它们。

通常当您收到类似的错误时,这是​​由于包含文件中的问题。所以错误可能在 ServerResponseRecord.h 中,认为它可能被实际使用它声明的对象所触发。如果没有看到完整的标题,就不可能确切地说出发生了什么。

【讨论】:

  • 如果ServerResponseRecord有问题,为什么我把type改成id我的代码还能编译运行?
  • 因为预处理器是一个棘手的东西,一些扩展可能只在某些情况下触发,而在其他情况下不会触发。如果您孤立地查看文件,假设 ServerRequest 和 ServerResponseRecord 具有有效定义,这似乎很好。通过使用@class 向前声明它们,您已经证明了这一点,这意味着您的其他标头之一中存在潜在错误,仅在某些情况下触发。
猜你喜欢
  • 2011-06-05
  • 2015-04-24
  • 1970-01-01
  • 1970-01-01
  • 2011-08-28
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多