【问题标题】:Where various variable and method types should be placed in a header应将各种变量和方法类型放在标头中的位置
【发布时间】:2012-06-15 22:46:39
【问题描述】:

我注意到,如果我将某些声明放在头文件的某些位置,则会出现编译错误。我已经将 cmets 放入了我认为某些事情的去向的代码中;他们是对的吗?

@interface Level : CCNode { 
    //Instance variables?
    PlayBackgroundLayer* playBGLayer;
    PlayUILayer* playUILayer;
    PlayElementLayer* playElementLayer;
}

//Static methods?
+(void) InitLevel: (int) levelNumber;
+(Level*) GetCurrentLevel;

//Property declarations for instance variables?
@property (nonatomic, retain) PlayBackgroundLayer* playBGLayer;
@end

//Static variables?
Level* currentLevel;
PlayTilemapLayer* playTilemapLayer;

【问题讨论】:

    标签: objective-c variables compiler-errors declaration header-files


    【解决方案1】:

    你在所有方面都是正确的,除了一个。您的最后一个变量不是静态变量,它们是全局变量。静态变量只是用 static 关键字声明的变量,它们的含义与其他语言略有不同。它们不是类变量,它们是仅对声明它们的文件可见的变量,并且只有在声明它的范围内才可见(如果您在函数中声明它,其他函数将看不到它)。但是,正如您所料,无论您有多少实例,它们都只声明一次。如果您在接口之外声明某些内容而没有像您所做的那样使用 static 关键字,其他类将导入它们。但是,这不是实现此目的的理想方法(如果多个类导入此标头,您可能会遇到重新定义错误)。

    另外,一个警告是,属性不需要有一个明确的支持变量(如果你使用 @synthesize 关键字,编译器会为你创建一个),但是如果你想要一个,当然没有错用它。

    最后,您应该注意,您的静态方法 类方法不是实例方法的唯一原因是因为它们以 加号 (+) 字符而不是 减号 (-) 字符开头。

    【讨论】:

    • 不是静态方法,类方法。
    • 我一直在交替使用这两个术语……你能指出区别吗?
    • :) 在我的回答中查看 bbum 帖子的链接。粗略地说,ObjC 中没有静态方法——人们只是这样称呼它们,因为在其他 OO 语言中,静态方法在某种程度上填补了类方法在 ObjC 中的作用。类方法实际上是元类的实例方法。
    • @JoshCaswell 我明白了,我想在这种情况下使用正确的术语。那么是不是不可能在 Obj-C 中声明一个静态方法呢?最接近的是我想的静态函数(在 C 中)
    • 不是。肯定有static 函数,与C 语言一样,它们的可见性有限。
    【解决方案2】:

    实例变量通常不需要显式声明。它们是在您 @synthesize 属性时创建的。但是,如果您确实需要它们,(新的)正确位置*位于 implementation 块的顶部:

    @implementation Level
    {
        PlayBackgroundLayer* playBGLayer;
        PlayUILayer* playUILayer;
        PlayElementLayer* playElementLayer;
    }
    

    那些不是静态方法,they're class methods,但是,是的,这就是你声明它们的地方。有些人喜欢将@property 声明放在类方法之前,但这是见仁见智的问题。实例方法在这两者之后,虽然从技术上讲顺序并不重要——也就是说,编译器不在乎,它只是一个可读性的问题。

    不过,那些顶级变量需要放在头文件以外的地方。如果你把它们放在那里,你会得到编译错误,因为每个导入头文件的文件似乎都在重新声明这些变量的存储空间,这是不允许的。

    通常您将此类变量放入 .m 文件中。如果您希望它们仅从那里可见,您将使用static。如果您希望它们在导入标头的其他文件中可见,请将 static 关闭并在标头中将变量声明为 extern

    extern Level* currentLevel;
    

    这让编译器知道变量的存储空间是在别处保留的。


    *参见 TOCPL 中的"Class Interface"

    【讨论】:

    • 那真的是新的正确的地方吗?我知道这种变化,但是否鼓励我们将它们放在实现中,而不是放在接口或接口私有类别中?
    • @borrrden:是的,请参阅我为 TOCPL 创建的链接,尤其是该部分中的“历史注释”。
    • 我有将所有私有实例变量移动到 .m 文件的 @interface Foo () 部分的习惯。但是,我相信受保护的实例变量(应该只对子类可用,而不是通过属性公开)仍然应该放在头文件中,对吗?
    • 默认情况下,实现块的 ivars 是@private,但可以更改为@protected。当然,如果您打算让其他开发人员对您的类进行子类化,您可能需要在标题中留下一些 ivars。
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2012-12-15
    • 2020-12-20
    • 2014-09-19
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多