可能重复:
How does an underscore in front of a variable in a cocoa objective-c class work?
注意:对于那些试图理解这一点的人们,我想出了我的困惑的根源。在.h中,我有:
...
@interface myClass : parentClass {
className *variableName:
}
@property (strong, nonatomic) className *variableName;
...
这导致self.variableName和_variableName是.m中的两个不同变量。我需要的是:
...
@interface myClass : parentClass {
className *_variableName:
}
@property (strong, nonatomic) className *variableName;
...
然后,在班级' .m,self.variableName和_variableName是等价的
全新的Xcode 4.5+,以ARC为目标,针对iOS 5.0+项目,使用_variableName
优于self.variableName
对比有明显的优势(运行时效率,速度等)旧式@synthesize variableName
?
我的理解是,Xcode 4.5+将创建一个等同于_variableName
的默认访问者self.variableName
,并且不使用@synthesize variableName
的唯一原因是为了避免iVars之间的混淆并传递 - 在变量中,对吗?
对我而言,仅使用self.variableName
访问iVar似乎是最直接和明确的,您正在寻找哪个变量。除了键入_
与self.
之外,使用_variableName
是否有优势?
答案 0 :(得分:16)
我的理解是Xcode 4.5+将创建一个默认的访问者“_variableName”,它等同于self.variableName,并且不使用“@synthesize variableName”的唯一原因是为了避免iVars和传入变量之间的混淆,正确?
在这种情况下,_variableName
不是访问者,它是由编译器自动生成并在自动@synthesized setter和getter中使用的ivar。通常,最好尽可能使用访问器(即self.variableName
),以便键值观察和绑定等工作适用于该属性。
当您直接访问ivar时,可以通过直接内存访问来访问它,就像访问结构中的数据一样。它只需要拥有ivar的对象的指针,抵消内存地址并尝试读取或写入该位置的内存。使用点表示法(self.variableName
)调用访问器方法来设置或获取该属性,并且可以在此过程中执行许多不同的操作,例如:
1)锁定:如果该属性将在多个线程中使用并且是atomic
属性,则运行时将自动执行某些锁定以确保该属性不是从多个线程同时访问。如果您的对象不打算在多个线程上使用,您可以在属性声明中提供nonatomic
提示,以便合成的访问者跳过锁定。
2)键值通知:属性的默认设置器调用-willChangeValueForKey:
和-didChangeValueForKey:
,它们会在更改属性时发送通知。如果使用绑定,以及任何其他键值观察,这对于任何正确更新都是必要的。
3)自定义访问者行为:如果您最终编写自己的setter和getter,那么您在其中实现的任何自定义内容。
从技术上讲,直接访问ivar比使用访问器更快,但是很少会出现明显的性能差异,并且可能是过早优化的情况。即使您不想立即使用上面列出的优势,最好还是使用访问器,这样如果您以后决定需要某些功能,则不必更改每个实例访问该变量(并可能在该过程中创建意外的新错误)。
此外,如果您直接访问ivars并最终将类重构为类别或子类,则会变得混乱,因为您通常必须将ivar声明为@protected
变量。如果您使用访问器,则不必执行此操作。
通常,我尝试只在init
,dealloc
和属性的访问者中直接访问ivars。很多工程师都遵循这个经验法则,因为有时在访问器中发生的自定义内容会导致意外行为,而对象是init
或dealloc
。例如,如果访问者中的任何内容导致您的对象retain
或release
,或者甚至形成对它的归零弱引用,则在dealloc
中使用时会导致崩溃。
答案 1 :(得分:5)
在最新的Xcode @synthesize
中是可选的。默认情况下,省略@synthesize
与编写
@synthesize someName = _someName;
使用@synthesize
的唯一原因是重命名为存储属性值而创建的实例变量,例如
@synthesize someName = someSpecialName;
当您使用self.variableName
访问变量时,您将浏览一个属性,这是一个为您访问实例变量的简短方法。尽管方法调度非常快,但它可能会为您执行其他服务,例如同步对变量的访问(在属性声明中指定atomic
或未指定nonatomic
时就是这种情况) )。在这种情况下,self.variableName
的访问速度会慢一些。如果在紧密循环中完成,这可能会产生影响。这就是您有时希望使用_variableName
直接访问基础实例变量的原因。