我对于通过self访问实例变量或仅通过名称(在类中工作时)之间的区别感到困惑。
例如,参加这个课程:
//In .h file:
@interface Register : NSObject {
NSString *mName;
}
- (id) initWithName:(NSString *) name;
//In .m file:
- (id) initWithName:(NSString *)name
{
if (self == [super init])
{
mName = name;
}
return self;
}
通过
访问实例变量之间的区别是什么self.mName = name;
VS
mName = name;
哪个不是@property且不是@ sythenize'd。
根据这个例子,说这是这个:
//In .h file:
@interface Manange_My_ViewsViewController : UIViewController {
IBOutlet UILabel *countLabel;
}
@property (nonatomic, retain) IBOutlet UILabel *countLabel;
//In .m file:
@synthesize countLabel;
- (void) updateLabel:(NSUInteger)count
{
countLabel.text = [NSString stringWithFormat:@"%d", count];
}
但是我说访问countLabel:
self.countLabel
有什么区别?
编辑:每个用户回答的第三个示例: 比如说iVar不是IBOutlet:
//In .h file:
@interface Fake : NSObject {
NSString *mVar;
}
@property (nonatomic, retain) NSString *mVar;
//In .m file:
@synthesize mVar;
mVar = @"";
VS
self.mVar = @"";
或者它是一样的 - 在第一个我们正在访问实际的实例变量,在第二个我们实际上是通过自动创建的setter(通过@synthesize)?
全部谢谢!
编辑:更新以响应Peter Hosey ......
所以你认为mVarName的约定很糟糕?我从C ++时代就开始了。
但是当你这样做的情况呢?
-(void) someMethod:(int) x
{
x = x;
}
你不能这样做(说'x'也是一个类变量)
但你可以这样做:
-(void) someMethod:(int) x
{
mX = x;
}
但是你说的更好:
-(void) someMethod:(int) x
{
self.x = x;
}
答案 0 :(得分:7)
通过
访问实例变量之间的区别是什么self.mName = name;
VS
mName = name;
首先是属性访问语法。它转换为对象的访问者消息(在本例中为self
)。也就是说,该语句隐式转换为此消息表达式语句:
[self setMName:name];
(类似的尴尬访问者名称是为什么“mName”是一个糟糕的属性名称。有一个属性声明语法来解决这个问题,让你命名属性“name”和你的实例变量“mName”并映射一个到另一个。)
第二个示例直接访问实例变量 - 无访问者消息。
哪个不是@property且不是@ sythenize'd。
虽然说这是......,
如果没有为类声明名为“mName
”的属性,则不能使用属性访问语法在该类的实例上按该名称访问属性。
无论您是否合成访问器,将它们手动传递给具有@dynamic
的超类,或者自己定义它们都无关紧要。这就是对象如何响应访问者消息,但编译器生成的访问者消息也没有什么不同(因为属性访问可以很容易地来自类外部而不是来自内部)。
说它iVar不是IBOutlet:
那没关系。 IBOutlet仅对IB有意义。其他一切都不关心。
事实上,IBOutlet目前只是一个扩展为空的宏。在对代码进行预处理之后,单词“IBOutlet”不再存在,因此编译器永远不会看到它。除了IB之外,这对于任何事情都没有什么区别:完全没有。
我说mName
作为属性名称是不好的,因为它后面有访问者名称。实例变量的名称是一个单独的问题,特别是因为属性和ivar不必具有相同的名称。
对于变量,无论是实例变量还是局部变量,name
或m_name
或mName
的选择纯粹是样式选择。
someMethod:
通常是访问者setX:
。在该方法中,self.x = x
([self setX:x]
)会导致无限递归。所以不要这样做。
当someMethod:
不是访问者(或init
或dealloc
)时,使用该属性就可以了,通常更可取。但是,在这种情况下,您不可能给它的一个参数赋予与实例变量相同的名称。如果出现这种情况,请更具体地命名局部变量,因为其目的更具体。这也是一个风格问题。
当它是访问者时,我将局部变量newX
命名为,将实例变量命名为与属性x
相同。这是我个人的风格;正如我所说,命名属性x
,ivar mX
和局部变量x
也很好(除了这个例子的过分简洁)。
答案 1 :(得分:3)
好的,先关闭是基本的区别:
mVar = var;
这只是改变一个值。就是这样。
self.mVar = var;
这相当于:
[self setMVar:var];
换句话说,一个调用一个方法,另一个不调用。使用@property
语法可以为您带来一些非常好的好处。例如,您可以免费获得键值编码合规性。这意味着另一个对象可以观察到该对象的mVar
属性,并在其发生更改时自动得到通知,无需执行任何操作。如果你直接访问ivar,你就不会得到这个。 (当然,除非你自己实现它。但你为什么要那样做?)
您还可以获得半免费内存管理。如果您将某个属性声明为(retain)
,那么您自己就不必[newValue retain]
。合成的方法将为您执行此操作(在这两种情况下,您仍需要[ivar release]
方法中的dealloc
。
您还可以获得某种程度的线程安全性。如果您没有将属性声明为(nonatomic)
,那么它(默认情况下)是atomic
(尽管该关键字不存在;它隐含着)。这意味着读取/更新属性的值为atomic operation。如果你只是直接访问ivar,你必须自己用锁来实现原子性。
基本上,使用合成的方法可以免费获得一些非常简洁的东西。我对不使用@property
语法的唯一原因是,如果您有无可辩驳的证据表明调用这些方法是代码中的瓶颈。但是,如果情况确实如此,
答案 2 :(得分:1)
首先,有一个只读属性 - 一个IBOutlet本质上是 - 它并不重要。
关键区别在于,在直接访问实例变量时,该属性实际上正在调用访问器方法。
因此,为了设置retain属性,使用self和访问器将释放旧对象并保留新对象。直接设置实例变量不会影响任何对象的保留计数。
使用@synthesize
将为您生成标准访问者。
使用属性的关键原因是,由于它们是访问器,因此可以从类外部读取和/或修改它们。