代码之家  ›  专栏  ›  技术社区  ›  gargantuan

Cocoa:在头文件中导入和在主文件中导入有什么区别?

  •  7
  • gargantuan  · 技术社区  · 16 年前

    我不知道为什么,但有时我设法修复了一些编译错误,最明显的是

    error expected specifier-qualifier-list before 'someClass'
    

    #import "someClass.h"

    一些粗略的谷歌搜索已经找到了答案“永远不要在头文件中导入头文件”,这就是建议停止的地方。

    要么是我完全编造出来的,要么是我从某个地方养成的习惯,但我认为页眉就是要导入页眉的地方。显然不是,但有人能向我解释为什么会这样,以及导入标题的首选方式是什么?

    3 回复  |  直到 16 年前
        1
  •  10
  •   Community Mohan Dere    9 年前

    除非您是从要包含的类继承,否则不应在头中包含头。 如果需要将对象包含为接口变量,则应使用 @class 而是指令;这将告诉编译器标识符引用了一个类。

    编译器将知道您的实例变量是指向对象的指针,但在解析标头时它不知道对象的详细信息。它需要知道的只是它是一个类。然后,编译器在解析实现文件时可以看到类的方法;此时,它确实需要类来验证它是否响应您发送的消息。


    更新: 我本打算更新我的答案,以回答后面的一些问题,但是 Rob Napier has a good follow-up

        2
  •  13
  •   Rob Napier    16 年前

    约翰给出了很好的建议,但这里有一些关于为什么、为什么和例外的背景。

    A.h 进入 B.h 进口 B.h C.h ,那么每次你在 A.h ,您必须重新编译 C.m C.m 不使用中定义的任何内容 . 这可能会导致非常糟糕和不必要的构建搅动,特别是如果您的头经常更改(这在开发的早期阶段很常见)。

    A.h 参考类 B 和 B.h 参考类 A . 事实上,这种情况经常发生,并且会很天真地潜入一个系统。集合对象可能引用其包含的对象的类型,并且对象可能引用集合对象的类型。它只需要一个引用,因为某个方法接受或返回该类型。如果您有导入其他头的头,那么发生这种情况的可能性很快接近统一。最终会出现递归导入,编译时错误可能会让人大吃一惊。”我 知道 这就是定义!就在那里!是进口的!”但是,导入时它还没有被解析 这 标题。这就是导致上述错误的原因。

    因此,即使您不太关心构建时间(尽管您应该),也要避免将头导入头中。。。除了

    一些标题可以帮助你 有 进口。当然是你的超类。定义 @protocol 你实施或 typedef 你用。所以,是的,你必须包括这些。

    那么系统头呢?好吧,它们永远不会导致搅动,而且显然它们不会导致递归导入,所以它们很好。我不鼓励人们使用 @class 转发系统标题中的内容声明。它会为标题的用户创建额外的工作,没有任何值。为了保持良好的标题卫生,请记住将系统标题括在<尖括号>和你的标题在“引号”中。

    所以这不是一个简单的问题,但简单的规则是:在编译器允许的任何时候,避免将用户头导入到其他用户头中。

        3
  •  0
  •   Adrian    16 年前

    您不仅要将头包含到实现文件中,还要包含到使用该类的其他文件中。如果在标头中包含所有依赖项,则仅用于使用该标头定义的特定类的所有其他文件(包括该标头)本身也将包含所有依赖项。

    这不仅会产生噪音,而且会在类引用自身时导致问题。每个类都必须在另一个类之前导入,这导致首先导入一个类,然后找不到另一个类的类型。这导致您发布了一条神秘的错误消息,这基本上意味着编译器无法找到 someClass 类型。

    @class , @protocol 等)您可以避免这些问题。