【发布时间】:2010-11-01 07:12:42
【问题描述】:
我可以理解在头文件的@interface中定义函数,但是为什么是实例变量呢?实例变量不应该是私有的,只能通过消息访问吗?
【问题讨论】:
标签: objective-c
我可以理解在头文件的@interface中定义函数,但是为什么是实例变量呢?实例变量不应该是私有的,只能通过消息访问吗?
【问题讨论】:
标签: objective-c
原因是它可以计算子类的变量偏移量。
@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
}
这有一个副作用:如果您更改库中类的大小,则会破坏链接到该库的应用程序中的所有子类。新属性解决了这个问题。
【讨论】:
虽然它们是在头文件中声明的,但默认情况下,Objective-C 中的所有实例变量都具有@protected 访问权限。这意味着该变量可以在声明它的类以及从该类继承的任何类中访问。
这是 Apple 关于定义 Objective-C 类的文档:Defining Classes
请注意标题为“实例变量的范围”的部分。
【讨论】:
我认为这是一个技术问题。如果我理解正确的话,Objective-C 类只是一个花哨的 C 结构。对于要使用的结构,它的大小必须是已知的。 (就像 sizeof() 否则如何工作)
【讨论】:
如果有人偶然发现这个问题——从带有 LLVM 编译器的 XCode 4.2 开始,您可以使用以下大括号表示法在 @implementation 中声明实例变量:
@interface SomeClass : NSObject
@end
@implementation SomeClass {
NSString *myInstanceVariable_;
}
- (void)moreMethods {}
@end
实例变量通常不应该是你的类声明的公共接口的一部分——它们是 实现细节。
但是,确保您在大括号内定义实例变量,否则您将定义一个与对象实例无关的全局变量:
@implementation SomeClass
NSString *whoopsGlobalVariable_;
- (void)moreMethods {}
@end
【讨论】:
摘自 Apple 文档中关于定义 Objective-C 类的部分,The Role of the Interface:
虽然实例变量最自然地被视为类的实现而不是其接口,但它们仍然必须在接口文件中声明。这是因为编译器必须知道对象的结构在哪里使用,而不仅仅是在哪里定义。
【讨论】:
注意,在 Objective C 2.0 新的“Modern Runtime”下(在 iPhone 应用程序和 64 位 Mac OS X 10.5 应用程序中可用)您不需要指定 ivars,您可以指定属性然后使用 @synthesize 来生成 ivars。
这是因为在 Modern Runtime 中,ivars 有一个全局间接符号来保存 ivar 的偏移量。这也解决了脆弱的基类问题,允许重新排序和添加 ivars 而无需重新编译子类(删除或重命名 ivars 仍可能导致链接错误)。
但是您仍然必须在主界面中列出属性,因此似乎没有任何方法可以完全隐藏私有 ivars,这是不幸的。例如,您不能在类别中使用属性和 @synthesize。
【讨论】: