【问题标题】:Do declared properties require a corresponding instance variable?声明的属性是否需要相应的实例变量?
【发布时间】:2011-03-05 16:37:53
【问题描述】:

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

MyObject.h

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

MyObject.m

@implementation
@synthesize name;
@end

但是,如果我这样做会怎样:

MyObject.h

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

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

【问题讨论】:

  • 为什么第二个'MyObject.h'粗体不是'MyObject.m'?

标签: objective-c instance-variables declared-property


【解决方案1】:

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

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

【讨论】:

    【解决方案2】:

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

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

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

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

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

    【讨论】:

    • 现在不是强制写 @synthesize 了。那么在这种情况下这个答案如何有效!
    • 您不必声明 @property...@synthesize。使用 synthesize 使您不必在实现中编写 getter/setter。如果你不合成,那么你必须滚动你自己的getter/setter
    • @PapaSmurf 这是不正确的。您可以使用@property,不使用@synthesize,而不是自己实现它们。编译器将自动为您synthesize,而无需再编写。
    【解决方案3】:

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

    【讨论】:

      【解决方案4】:

      来自文档:

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

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

      【讨论】:

        【解决方案5】:

        如果您使用的是 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;
        

        【讨论】:

          【解决方案6】:

          The Objective-C Programming Language: Property Implementation Directives

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

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

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

          【讨论】:

            猜你喜欢
            • 2014-06-20
            • 1970-01-01
            • 2013-09-17
            • 2012-02-21
            • 2013-10-11
            • 2018-11-26
            • 2020-10-10
            • 2012-07-15
            • 2012-11-28
            相关资源
            最近更新 更多