Objective-C中的属性声明

6
可能是重复问题: 在 Cocoa Objective-C 类中,变量前面的下划线是如何工作的? 我发现当你想合成属性时,需要使用下划线,但这对我来说毫无意义。
那么,让我们开始吧。 在我们的 .h 文件中,我们写下以下代码:
@property (nonatomic) double speed;

在我们的.m文件中,我们这样操作:
@synthesize speed = _speed;

为什么?据我所知,属性会创建一个实例变量并为其创建设置器和获取器。但是最后一行 "

" 是什么意思呢?
@synthesize speed = _speed 

做什么?

常识告诉我们,我们将 _speed 的值赋给 speed。好的。
我们在哪里声明了 _speed?为什么编译器不给我们报错?它应该意味着什么?为什么代码如此难懂?

我的问题是:

如果我只做

@synthesize speed;

没有_speed,我会得到错误或一些bug吗?这个语法的原因是什么?在创造它时他们在想什么?_speed来自哪里?它是什么?它是一个指针还是一个真实的值?到底发生了什么?


请参见https://dev59.com/VXA75IYBdhLWcg3wAUF9。 - msk
4
自从物业被引入以来,这个问题每天都被问到大约两次... 我只是稍微夸张了一点。 - Matt Wilding
肯定是这样,但随着LLVM Clang的演变,答案也在发生变化。你可以削减所有无关的内容,只保留今天的属性声明。而上周则不一定是这样的。 - fabrice truillot de chambrier
1
@fabricetruillotdechambrier 确实,我一直在享受最近Xcode测试版的所有功能。修改之前的800个问题和答案肯定比向池中添加更多问题更好 =) - Matt Wilding
4
这里有16个重复的链接:https://dev59.com/k2035IYBdhLWcg3wK8wm/ https://dev59.com/2m025IYBdhLWcg3wW0yx/ https://dev59.com/bUzSa4cB1Zd3GeqPllSe/ https://dev59.com/4Gw05IYBdhLWcg3wiybg/ http://stackoverflow.com/q/5659156 https://dev59.com/_3RA5IYBdhLWcg3wwwzD/ http://stackoverflow.com/q/6146244/ http://stackoverflow.com/q/10651535/ https://dev59.com/CFfUa4cB1Zd3GeqPJI93/ https://dev59.com/-13Ua4cB1Zd3GeqP-0bQ/ https://dev59.com/VXA75IYBdhLWcg3wAUF9/ http://stackoverflow.com/q/6064283/ http://stackoverflow.com/q/9696359/ http://stackoverflow.com/q/5521499/ https://dev59.com/Cm035IYBdhLWcg3wW-z1/ https://dev59.com/r3I95IYBdhLWcg3w3iDG/ - jscs
7个回答

5

好的,_speed 是由该属性使用的实例变量。如果您真的想要完全声明它,您需要写成:

@interface Foo
{
    double _speed;
}

@property double speed;

@end

@implementation Foo

@synthetize speed = _speed;

@end

现在Xcode 4.4已经发布,大部分的内容都是不必要的,应该忽略以保证开发的正常进行。

基本上,您只需要做以下几点:

@interface Foo

@property double speed;

@end

没有实例变量,没有 @synthetize,但一切仍然像以前一样工作。您可以使用 self.speed 或 self->_speed 进行直接访问。

这就是为什么我喜欢苹果,每个版本都让生活变得更加简单。感谢您的见解。 - Dvole
小提示:Xcode 4.4 只适用于 Mountain Lion 的 OSX 开发人员使用,而 Xcode 4.5 只能与 iOS 6 SDK beta 一起使用。4.3.x 是最新的公共版本,但仍需要 @synthesize - Matt Wilding
4.4可以在Lion上运行,我刚在developer.apple.com检查了一下,并且现在可以用来提交应用程序。 - fabrice truillot de chambrier
仍需要使用@synthesize speed; - cprcrack

1

好的,你不必这样做...

然而,这样做意味着在你的实现中,你不能使用该属性的非下划线名称,因为事实上这样做会混淆直接访问iVar和通过属性访问iVar。

换句话说,通过这样做:

@synthesize myProperty;

在您的代码中,您可以通过myPropertyiVar)或self.myProperty(属性 - 具有访问规则 - readonly/readwrite、getter、setter等)引用它。如果您正在使用某种规则,这可能会令人困惑:
@property(nonatomic, retain, getter = anotherProperty) NSNumber myProperty

通过在代码中访问myProperty,您期望获得anotherProperty的值。

只有通过执行以下操作才能实现:

self.myProperty

因此,在Objective-C中,我们可以采取以下措施来避免这种情况:

@synthesize myProperty = _myProperty;

因此,在代码中直接引用myProperty实际上是一个错误,而应该使用self.myProperty(属性访问)或_myProperty(iVar访问)。

1

你不一定需要这样做。这只是常见的做法。...=_speed 将创建一个名为 _speed 的属性,它的 setter 和 getter 将被命名为 speed。这使您可以区分

self.speed = value;

speed = value; 

因为后者会导致编译错误。

_speed = value; 

在这种情况下,这将是正确的。

这有助于避免保留/释放相关错误,因为setter将保留对象,而简单的赋值不会。 (self.speed = ...将调用setter!)

如果您在synthesize语句上省略了“=_speed”,则属性仅命名为“speed”。如果您没有犯任何错误,则这将完美地工作。


0

不会有任何问题 -- 直接写 @synthesize speed 就可以了。使用 _speed 只是将底层实例变量命名为 _speed 而不是 speed。大多数人这样做是为了避免直接访问 ivar,而是通过 getter 访问。


0

来自文档

@synthesize speed = _speed;将属性speed指向实例变量_speed

你不必这样做。@synthesize speed同样可以正常工作。


0

这是一种命名约定,你不必非得这么做。人们倾向于这样做是为了区分实例变量和属性。

通常是这样的

.h

@interface myClass : NSObject
{
    NSNumber *_speed
}

@property (nonatomic, strong) NSNumber *speed;

.m

@implementation
@syntesize speed = _speed;

0

在手动内存管理的环境中:

为什么我需要实例变量名?

  1. 您需要释放 dealloc 中可能使用的属性所占用的内存。
  2. 您可以使用 self.field = nil,但这种方法可能会导致问题
  3. 因此,您需要一个实例变量,该变量在属性后面使用,以便您可以在 dealloc 中对其进行 [_field release];

如果您需要在初始化程序中访问属性,则同样适用。

为什么我需要在实例变量名中加下划线?

  • 为了永远不会意外地直接使用 ivar 并破坏属性的内存管理协议。

@property (retain) UILabel *label;

...

@synthesize label;

...

-(void)viewDidLoad {
   [super viewDidLoad];

   label = [[[UILabel alloc] initWithFrame:frame] autorelease];
}

在这里,如果不小心漏写了 self,你就可能会出现悬空指针的问题。如果你在代码上方使用了 @synthesize label = _label;,那么这个错误将会被编译器捕捉到。

  • 局部变量或者方法参数的名称通常和属性名称相同 - 如果你使用下划线开头的实例变量,就不会产生任何问题。

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接