类属性 mVar 和实例变量 self.mVar 之间的区别
我对通过 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。
但是,
//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;
}
I am some what confused as to the difference between accessing an instance variable via self or just by name (when working inside the class).
For instance, take this class:
//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;
}
What's the difference between accessing the instance variable via
self.mName = name;
vs
mName = name;
Which isn't a @property and is not @sythenize'd.
Say it is this though, per this example:
//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];
}
But say I accessed countLabel as:
self.countLabel
What would be the difference?
Edit: Third example per users' answer:
Say it the iVar wasn't an IBOutlet:
//In .h file:
@interface Fake : NSObject {
NSString *mVar;
}
@property (nonatomic, retain) NSString *mVar;
//In .m file:
@synthesize mVar;
mVar = @"";
VS
self.mVar = @"";
Or is it the same - that in the first we are accessing the actual instance variable and in the second we're actually going through the auto created setter (via @synthesize)?
Thanks all!
Edit: Update in response to Peter Hosey ...
So your thinking the convention of mVarName is bad? I took that from my C++ days.
But what about the case when you do?
-(void) someMethod:(int) x
{
x = x;
}
You can't do that (Say 'x' is also a class variable)
But you can do:
-(void) someMethod:(int) x
{
mX = x;
}
But your saying its better to do:
-(void) someMethod:(int) x
{
self.x = x;
}
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。
绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论
评论(3)
首先是属性访问语法。它转换为对象的访问器消息(在本例中为
self
)。也就是说,该语句隐式转换为以下消息表达式语句:(像这样的尴尬访问器名称就是为什么“mName”对于属性来说是一个糟糕的名称。有属性声明语法可以解决这个问题,让您将属性命名为“name”和实例变量“mName”并将一个映射到另一个。)
第二个示例直接访问实例变量——没有访问器消息。
如果没有为类声明名为“
mName
”的属性,则您无法使用属性访问语法来访问该类实例上的该名称的属性。无论您是合成访问器、使用
@dynamic
将它们手动传递给超类还是自己定义它们,这都无关紧要。这就是对象响应访问器消息的方式,但编译器生成的访问器消息不会有什么不同(因为属性访问可以很容易地来自类外部和类内部)。这并不重要。 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
、ivarmX
和局部变量x
也很好(除了这个过于简洁之外)例子)。The first is property access syntax. It translates to an accessor message to the object (in this case,
self
). That is, that statement implicitly translates to this message expression statement:(Awkward accessor names like that are why “mName” is a poor name for a property. There is property declaration syntax to work around that, letting you name the property “name” and your instance variable “mName” and map one to the other.)
The second example directly accesses the instance variable—no accessor message.
If no property named “
mName
” is declared for a class, then you can't use property access syntax to access a property by that name on an instance of that class.And it doesn't matter whether you synthesize the accessors, hand-wave them to a superclass with
@dynamic
, or define them yourself. That's how the object will respond to the accessor message, but the accessor message the compiler generates will be no different (since a property access could just as easily come from outside the class as from inside it).That doesn't matter. IBOutlet only means anything to IB. Everything else doesn't care.
In fact, IBOutlet is currently just a macro that expands to nothing. After your code gets preprocessed, the word “IBOutlet” is no longer there, so the compiler never sees it. That's how little a difference it makes to anything but IB: None at all.
Edit in response to question edit
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
orm_name
ormName
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 (orinit
ordealloc
), 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 propertyx
, the ivarmX
, and the local variablex
is fine too (aside from the excessive brevity of this example).好的,首先是基本的区别:
这只是改变一个值。就是这样。
这相当于:
换句话说,一个调用方法,另一个不调用。使用@property语法可以给你带来一些非常好的好处。例如,您可以免费获得键值编码合规性。这意味着另一个对象可以观察该对象的
mVar
属性,并在其更改时自动收到通知,无需您执行任何操作。如果您直接访问 ivar,则不会得到此信息。 (当然,除非您自己实现它。但是您为什么要这样做?)您还可以获得半自由内存管理。如果您将属性声明为
(retain)
,则您不必自己[newValue keep]
。合成方法将为您执行此操作(在这两种情况下,您仍然需要在dealloc
方法中使用[ivar release]
)。您还可以获得一定程度的线程安全性。如果您没有将属性声明为
(nonatomic)
,那么它(默认情况下)是atomic
(尽管该关键字不存在;它是隐含的)。这意味着读取/更新属性的值是一个原子操作。如果您只是直接访问 ivar,则必须自己使用锁来实现原子性。基本上,使用综合方法可以让你免费得到一些非常好的东西。我要说不使用
@property
语法的唯一原因是,如果您有无可辩驳的证据表明调用这些方法是代码中的瓶颈。然而,您将真的很难想出一种情况来实现这种情况。OK, first off is the basic difference:
This is just changing a value. That's it.
This is equivalent to:
In other words, one invokes a method, the other does not. Using the
@property
syntax can give you some really neat benefits. For example, you get key-value coding compliance for free. That means that another object can observe this object'smVar
property, and be automatically notified whenever it changes, without you doing anything. You don't get this if you just access the ivar directly. (Unless, of course, you implement it yourself. But why would you do that?)You also get semi-free memory management. If you declare a property as
(retain)
, then you don't have to[newValue retain]
yourself. The synthesized method will do this for you (in both cases, you'd still have to[ivar release]
in yourdealloc
method).You also can get some degree of thread safety. If you don't declare a property as
(nonatomic)
, then it is (by default)atomic
(although that keyword does not exist; it's implied). That means that reading/updating the value of the property is an atomic operation. If you were to just access the ivar directly, you'd have to implement the atomicity yourself with a lock.Basically, using the synthesized methods gets you some really neat stuff for free. The only reason I'd say to not use the
@property
syntax is if you have irrefutable evidence that invoking those methods is a bottleneck in your code. However, you'll be really hard pressed to come up with a situation where that would be the case.首先,对于只读属性(IBOutlet 本质上就是这样),它并不那么重要。
关键区别在于,属性实际上是在调用访问器方法,而实例变量是直接访问的。
因此,为了设置保留属性,使用 self 和访问器将释放旧对象并保留新对象。直接设置实例变量不会影响任何对象的保留计数。
使用
@synthesize
将为您生成标准访问器。使用属性的关键原因是,由于它们是访问器,因此可以从类外部读取和/或修改它们。
First of all, with a read-only property--which an IBOutlet essentially is--it does not matter as much.
The key difference is that the property is actually calling the accessor method while the instance variable is being accessed directly.
Thus, for setting a retain property, using self and the accessor will release the old object and retain the new one. Setting the instance variable directly will NOT impact the retain counts of any objects.
Using
@synthesize
will generate standard accessors for you.The key reason to use properties is that, since they are accessors, they can be read and/or modified from outside the class.