为什么我必须在头文件中定义两次变量?这些变量之间有什么不同?
第一个定义是:
@interface MyController: UIViewController
{
NSInteger selectedIndex;
}
第二个定义是:
@property (nonatomic) NSInteger selectedIndex;
答案 0 :(得分:6)
早期版本的Objective-C需要您所看到的内容, 但现在已不复存在了。
NeXT使用的Objective-C的第一个版本直到新版本 引入了运行时(在Mac OS X上使用Objective-C 2.0) 实例变量必须声明为类结构的一部分 在
@interface
中。原因是,如果你继承了一个类, 编译器需要知道类的实例变量布局 所以它可以看到放置子类的实例的偏移量 变量当引入属性时,必须具有合成属性 由类结构中的实例变量“支持”。因此 你必须声明一个实例变量和属性。
以上所有情况都不再适用。较新的Objective-C不那么脆弱 在它查找实例变量偏移的方式,这意味着一个 几点变化:
- 并非所有实例变量都必须位于
@interface
中。现在可以在@implementation
中定义它们:尽管不在类别中 关于冲突和其他问题的可能性。- 可以根据属性定义推断和创建合成属性的实例变量。
- 您可以以编程方式将实例变量添加到您在运行时创建的类中(仅在您将类注册为之前) 可供系统使用)。
因此,重申一下,您只需要声明两个实例 旧版本中的变量和合成属性 Objective-C语言。你所看到的是多余的,不应该 被视为“最佳实践”。
答案 1 :(得分:4)
正如其他人所指出的那样,不再需要为标题中的合成属性声明支持实例变量。
为了使这一点更清楚:你所看到的不是同一个变量的两个声明,它是变量的一个声明和属性的一个声明。
属性基本上是一组通常用于访问实例变量的方法(在本例中为selectedIndex
和setSelectedIndex:
)。属性和实例变量之间存在差异。属性的setter / getter可以做的不仅仅是设置变量,在你的例子中,它也可以例如更新UI以反映所选索引的更改,或者getter可以从其他一些变量推断索引(在这种情况下,可能存在选择索引路径)等。
合成属性只是让您自己实现这些方法并为您提供简单设置变量的默认实现,但您也可以自己实现selectedIndex
和setSelectedIndex:
,就像其他方法一样如果您需要实例变量本身或完全省略它(在推断属性的情况下)。
答案 2 :(得分:3)
在现代运行时,您不需要声明它们两次。只需使用:
在你.h
@property (nonatomic) NSInteger selectedIndex;
{}之间的部分是iVar的声明。使用@property,您可以声明getter和setter。在现代运行时,如果您只使用上面的代码,则说基本相同(您的iVar现在是_selectedIndex)。