类属性mVar和实例变量self.mVar之间的区别

时间:2010-02-17 04:49:12

标签: iphone objective-c oop self core-foundation

我对于通过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;
}

3 个答案:

答案 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不必具有相同的名称。

对于变量,无论是实例变量还是局部变量,namem_namemName的选择纯粹是样式选择。

someMethod:通常是访问者setX:。在该方法中,self.x = x[self setX:x])会导致无限递归。所以不要这样做。

someMethod:不是访问者(或initdealloc)时,使用该属性就可以了,通常更可取。但是,在这种情况下,您不可能给它的一个参数赋予与实例变量相同的名称。如果出现这种情况,请更具体地命名局部变量,因为其目的更具体。这也是一个风格问题。

当它是访问者时,我将局部变量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将为您生成标准访问者。

使用属性的关键原因是,由于它们是访问器,因此可以从类外部读取和/或修改它们。