为什么在Objective-C的头文件中定义了实例变量

时间:2009-06-08 20:39:11

标签: objective-c

我可以理解在头文件的@interface中定义函数,但为什么实例变量?实例变量不应该是私有的,只能通过消息访问吗?

6 个答案:

答案 0 :(得分:8)

原因是它可以计算子类变量的偏移量。

@interface Bird : NSObject {
    int wingspan;
}
@end
@interface Penguin : Bird {
    NSPoint nestLocation;
    Penguin *mate;
}
@end

在不知道“Bird”类的结构的情况下,“Penguin”类无法从结构的开头计算其字段的偏移量。企鹅结构看起来像这样:

struct Penguin {
    int refcount; // from NSObject
    int wingspan; // from Bird
    NSPoint nestLocation; // from Penguin
    Penguin *mate; // from Penguin
}

这有副作用:如果更改库中类的大小,则会中断链接到该库的应用程序中的所有子类。新属性解决了这个问题。

答案 1 :(得分:6)

虽然它们是在头文件中声明的,但是Objective-C中的所有实例变量都默认具有@protected访问权限。这意味着变量可以在声明它的类和从该类继承的任何类中访问。

以下是Apple关于定义Objective-C类的文档:Defining Classes

请注意标题为“实例变量的范围”的部分。

答案 2 :(得分:6)

我认为这是一个技术问题。如果我理解正确,Objective-C类只是一个奇特的C结构。对于要使用的结构,必须知道它的大小。 (就像sizeof()如何工作)

答案 3 :(得分:5)

如果有人遇到这个问题 - 从使用LLVM编译器的XCode 4.2开始,您可以使用以下括号表示法在@implementation中声明实例变量:


@interface SomeClass : NSObject
@end

@implementation SomeClass {
  NSString *myInstanceVariable_;
}

- (void)moreMethods {}
@end

实例变量通常不应该是您声明的公共接口的类的一部分 - 它们是 实施细节。

但是, 确实 您在大括号内定义了实例变量,否则您将定义一个与对象实例无关的全局变量:


@implementation SomeClass
  NSString *whoopsGlobalVariable_;

- (void)moreMethods {}

@end

答案 4 :(得分:3)

摘自Apple关于定义Objective-C类的文档部分,The Role of the Interface

  

尽管实例变量最自然地被视为类的实现而不是其接口,但它们必须在接口文件中声明。这是因为编译器必须知道使用它的对象的结构,而不仅仅是它被定义的位置。

答案 5 :(得分:2)

请注意,在Objective C 2.0新的“Modern Runtime”(可在iPhone应用程序和64位Mac OS X 10.5应用程序中使用)中,您不需要指定ivars,您可以指定属性然后使用@synthesize来生成ivars。

这是因为在Modern Runtime中,ivars有一个全局间接符号,用于保存ivar的偏移量。这也解决了脆弱的基类问题,允许重新排序和添加ivars而无需重新编译子类(删除或重命名ivars可能仍会导致链接错误)。

但是你仍然需要在主界面列出属性,所以似乎没有任何方法可以完全隐藏不幸的私人ivars。例如,您不能在类别中使用属性和@synthesize。