4

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

对比

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)?

谢谢大家!

编辑:响应彼得·霍西的更新......

所以你认为 mVarName 的约定不好?我是从我的 C++ 时代开始的。

但是当你这样做的时候呢?

-(void) someMethod:(int) x
{
    x = x;
}

你不能这样做(说'x'也是一个类变量)

但你可以这样做:

-(void) someMethod:(int) x
{
    mX = x;
}

但你说最好做:

-(void) someMethod:(int) x
{
    self.x = x;
}
4

3 回答 3

7

通过访问实例变量有什么区别

self.mName = name;

对比

mName = name;

第一个是属性访问语法。它转换为对象的访问者消息(在本例中为self)。也就是说,该语句隐式转换为该消息表达式语句:

[self setMName:name];

(像这样笨拙的访问器名称就是为什么“mName”是一个糟糕的属性名称的原因。有一个属性声明语法可以解决这个问题,让您将属性命名为“name”和您的实例变量“mName”并将一个映射到另一个.)

第二个例子直接访问实例变量——没有访问者消息。

这不是@property,也不是@sythenize'd。

不过说是这个,……</p>

如果没有为类声明名为“<code>mName”的属性,则不能使用属性访问语法在该类的实例上按该名称访问属性。

无论您是合成访问器,将它们手动挥动到超类@dynamic,还是自己定义它们,都无关紧要。这就是对象将如何响应访问器消息的方式,但编译器生成的访问器消息将没有什么不同(因为属性访问既可以来自类外部也可以来自其内部)。

说 iVar 不是 IBOutlet:

那没关系。IBOutlet 仅对 IB 意味着任何东西。其他的都不管。

事实上,IBOutlet 目前只是一个扩展为空的宏。在你的代码被预处理之后,“IBOutlet”这个词就不再存在了,所以编译器永远不会看到它。这就是它对除了 IB 之外的任何东西的影响很小:根本没有。

编辑以回应问题编辑

I said mName is bad as a property name, because of the accessor names that follow from it. The name of an instance variable is a separate issue, particularly since the property and ivar don't have to have the same name.

For a variable, be it an instance variable or a local variable, the choice of name or m_name or mName is purely a style choice.

someMethod: is generally the accessor, setX:. Within that method, self.x = x, which is [self setX:x], causes infinite recursion. So don't do that.

When someMethod: isn't the accessor (or init or dealloc), using the property is just fine and generally preferable. However, in that case, you're not likely to give one of its arguments the same name as an instance variable. When such a case could occur, name the local variable more specifically, because its purpose is more specific. This, too, is a style issue.

When it is the accessor, I name the local variable newX, having named the instance variable the same as the property, x. This is my own personal style; as I said, naming the property x, the ivar mX, and the local variable x is fine too (aside from the excessive brevity of this example).

于 2010-02-17T08:40:13.677 回答
3

好的,首先是基本区别:

mVar = var;

这只是改变一个值。就是这样。

self.mVar = var;

这相当于:

[self setMVar:var];

换句话说,一个调用一个方法,另一个不调用。使用@property语法可以给你一些非常好的好处。例如,您可以免费获得键值编码合规性。这意味着另一个对象可以观察到这个对象的mVar属性,并在它发生变化时自动得到通知,而无需您做任何事情。如果您只是直接访问 ivar,则不会得到此信息。(当然,除非你自己实现它。但你为什么要这样做呢?)

您还可以获得半自由内存管理。如果您将属性声明为(retain),那么您不必[newValue retain]自己声明。合成方法将为您执行此操作(在这两种情况下,您仍然必须使用[ivar release]您的dealloc方法)。

您还可以获得一定程度的线程安全。如果您不将属性声明为(nonatomic),那么它是(默认情况下)atomic(尽管该关键字不存在;它是隐含的)。这意味着读取/更新属性的值是原子操作。如果您只是直接访问 ivar,则必须自己使用锁来实现原子性。

基本上,使用综合方法可以免费获得一些非常整洁的东西。我要说使用@property语法的唯一原因是,如果您有无可辩驳的证据表明调用这些方法是代码中的瓶颈。然而,你真的很难想出一个会出现这种情况的情况。

于 2010-02-17T05:17:39.153 回答
1

首先,对于只读属性——IBOutlet 本质上是——它并不重要。

关键区别在于,该属性实际上是在直接访问实例变量时调用访问器方法。

因此,为了设置一个保留属性,使用 self 和访问器将释放旧对象并保留新对象。直接设置实例变量不会影响任何对象的保留计数。

使用@synthesize将为您生成标准访问器。

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

于 2010-02-17T05:01:49.113 回答