为什么在iOS应用中需要这个下划线前缀?
答案 0 :(得分:3)
有时候看看幕后发生的事情是有帮助的。基本上当你看到这个
@property (nonatomic, retain) Foo *foo;
在实施中使用
@synthesize foo=_foo;
以下是语法糖,这意味着编译器基本上为您生成了这段代码
Foo *foo = nil;
-(Foo *) foo {
return _foo;
}
-(void) setFoo:(Foo *)val {
if( _foo != val ) {
[_foo release];
_foo = [val retain];
}
}
这种方式当您引用公共属性时,您可以通过 self.foo 生成的附件来查看它,如果您想引用类中的实例变量,可以参考 _foo 即可。在XCode四之前,两者之间很容易混淆。你可以做点什么
self.foo = foo1;
foo = foo2;
这是完全合法的,可能导致几个级别的问题。第二行不使用访问器,因此不会保留foo2,这可能导致垃圾收集过早被拾取。更糟糕的是,第二行不使用会释放任何先前值的访问器,这意味着它会导致内存泄漏。
总而言之,新技术为您的属性创建了一个getter和setter,并允许您指定用于实例变量的名称,用于封装。
答案 1 :(得分:1)
这就是我有时这样做的原因:
如果我想对属性进行延迟加载,我通常会强调我的ivar,以便从后端服务器/已保存文件中加载所需数据的工作/只有你第一次加载。例如:
- (NSMutableArray *)recentHistory;
{
if (_recentHistory == nil)
{
// Get it and set it, otherwise no work is needed... hooray!
}
return _recentHistory;
}
所以这里调用属性[instanceOfClass recentHistory](或instanceOfClass.recentHistory)将检查ivar以查看是否需要加载数据或只返回已经加载的数据。
以这种方式声明所有属性真是太过分了。
希望有所帮助。
答案 2 :(得分:1)
只是想将我的想法添加到上述所有答案中。
在我的情况下,我主要是为了让我的班级免受意外伤害。
在我的.h文件中,我只声明没有ivars的属性。在.m文件中,我使用上面的@synthesize
模式来隐藏用户(包括我自己)的实际ivar,以强制使用合成/动态访问器,而不是直接使用其他ivars。你可以使用任何东西作为你的ivar名字,而不仅仅是强调它。例如你可以这样做:
@synthesize foo = _mySecretFoo;
@synthesize bar = oneUglyVarBecauseIHateMyBoss;
通过这种方式,你的老板只会看到吧,你会发现使用条形码访问器更方便,更安全 - 无论你使用点符号还是消息。
我更喜欢这种方法,
@property (getter=foo, setter=setFoo, ...) _mySecretFoo;
@property (getter=bar, setter=setBar, ...) oneUglyVarBecauseIHateMyBoss;
因为这不会强制执行私有实现和封装,而且当Xcode可以为您执行相同操作时,它只是额外的输入。有一点要记住,属性与ivars不一样!你可以拥有比ivars更多的属性,或者相反。
答案 3 :(得分:0)
保持ivar(实例变量)安全是一种惯例,因此您只能通过getter和setter访问它。