我可以理解在头文件的@interface中定义函数,但为什么实例变量?实例变量不应该是私有的,只能通过消息访问吗?
答案 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。