102

Objective-C 2.0 中的属性是否需要声明相应的实例变量?例如,我习惯做这样的事情:

我的对象.h

@interface MyObject : NSObject {
NSString *name;
}
@property (nonatomic, retain) NSString *name;
@end

我的对象.m

@implementation
@synthesize name;
@end

但是,如果我这样做了怎么办:

我的对象.h

@interface MyObject : NSObject {
}
@property (nonatomic, retain) NSString *name;
@end

这仍然有效吗?它和我之前的例子有什么不同吗?

4

6 回答 6

93

如果您使用的是 Modern Objective-C Runtime(iOS 3.x 或更高版本,或 64 位 Snow Leopard 或更高版本),那么在这种情况下,您无需为您的属性定义 ivars。

当您@synthesize拥有该属性时,ivar 实际上也会为您合成。这绕过了“脆弱的ivar”场景。您可以在Cocoa with Love上阅读更多相关信息

于 2010-06-19T04:26:31.143 回答
71

在您的界面中,您可以在大括号之间正式声明一个实例变量,或通过@property大括号外部声明,或两者兼而有之。无论哪种方式,它们都成为类的属性。不同之处在于,如果您声明@property,那么您可以实现 using @synthesize,它会为您自动编码您的 getter/setter。例如,自动编码器设置器将整数和浮点数初始化为零。如果您声明了一个实例变量,并且没有指定相应的@property,那么您不能使用@synthesize并且必须编写自己的 getter/setter。

您始终可以通过指定自己的方法来覆盖自动编码的 getter/setter。这通常通过managedObjectContext延迟加载的属性来完成。因此,您将 your 声明managedObjectContext为属性,然后还要编写一个-(NSManagedObjectContext *)managedObjectContext方法。回想一下,与实例变量/属性同名的方法是“getter”方法。

声明方法还允许您使用实例变量声明方法不允许的其他@property选项,例如retainand 。readonly基本上,ivar是旧方式,并@property对其进行扩展并使其更漂亮/更容易。您可以参考使用 self. 前缀与否,只要名称对于该类是唯一的就没有关系。否则,如果您的超类与您具有相同的属性名称,那么您必须说 self.name 或 super.name 以指定您正在谈论的名称。

因此,您会看到越来越少的人ivar在大括号之间声明 s,而是转向仅指定@property,然后执行@synthesize。如果@synthesize没有相应的@property. 合成器只知道@property规范中的属性类型。synthesize 语句还允许您重命名属性,以便您可以在代码中通过一个名称(简写)引用属性,但在 .h 文件外部使用全名。然而,随着 XCode 现在拥有的非常酷的自动完成功能,这不是一个优势,但仍然存在。

希望这有助于消除周围漂浮的所有混乱和错误信息。

于 2011-02-02T05:22:58.983 回答
8

它可以双向工作,但如果你不在花括号中声明它们,你将不会在 xcode 的调试器中看到它们的值。

于 2011-04-13T03:04:18.410 回答
3

从文档中:

一般来说,属性的行为在现代和传统运行时都是相同的(参见 Objective-C 运行时编程指南中的“运行时版本和平台”)。有一个关键区别:现代运行时支持实例变量合成,而传统运行时不支持。

要使 @synthesize 在旧版运行时中工作,您必须提供具有相同名称和兼容类型的属性的实例变量,或者在 @synthesize 语句中指定另一个现有实例变量。对于现代运行时,如果您不提供实例变量,编译器会为您添加一个。

于 2011-03-28T06:07:33.523 回答
3

如果您使用的是 XCode 4.4 或更高版本,它将为您生成实例变量合成代码。

您只需要声明如下属性;它将为您生成合成代码和实例变量声明代码。

@property (nonatomic, strong) NSString *name;

它将生成合成代码为

@synthesize name = _name;

并且您可以使用 _name 访问实例变量,它类似于声明

NSString* _name

但是如果你声明只读属性,它就像

@property (nonatomic, strong, readonly) NSString *name;

它将生成代码

@synthesize name;

或者

@synthesize name = name; 

因此,您应该以任何可以编写自己的合成代码的方式访问不带前缀“_”的即时变量名称,然后编译器将为您生成代码。你可以写

@synthesize name = _name;
于 2013-03-18T06:27:38.830 回答
1

Objective-C 编程语言:属性实现指令

存取器综合的行为因运行时而异(另请参阅“运行时差异”):

  • 对于旧版运行时,实例变量必须已经在当前类的 @interface 块中声明。如果存在与属性同名的实例变量,并且它的类型与属性的类型兼容,则使用它——否则,会出现编译器错误。

  • 对于现代运行时(参见 Objective-C 运行时编程指南中的“运行时版本和平台”),实例变量是根据需要合成的。如果同名的实例变量已经存在,则使用它。

于 2012-01-11T06:13:20.750 回答