What is the semantic difference between these 3 ways of using ivars and properties in objective-c?
这三种方法在objective-c中使用ivars和属性的语义区别是什么?
1.
1。
@class MyOtherObject;
@interface MyObject {
}
@property (nonatomic, retain) MyOtherObject *otherObj;
2.
2。
#import "MyOtherObject.h"
@interface MyObject {
MyOtherObject *otherObj;
}
@property (nonatomic, retain) MyOtherObject *otherObj;
3.
3所示。
#import "MyOtherObject.h"
@interface MyObject {
MyOtherObject *otherObj;
}
2 个解决方案
#1
56
Number 1 differs from the other two by forward declaring the MyOtherObject class to minimize the amount of code seen by the compiler and linker and also potentially avoid circular references. If you do it this way remember to put the #import into the .m file.
第1号不同于另外两个,它向前声明MyOtherObject类,以最小化编译器和链接器看到的代码量,并可能避免循环引用。如果您这样做,请记住将#import放入.m文件中。
By declaring an @property, (and matching @synthesize in the .m) file, you auto-generate accessor methods with the memory semantics handled how you specify. The rule of thumb for most objects is Retain, but NSStrings, for instance should use Copy. Whereas Singletons and Delegates should usually use Assign. Hand-writing accessors is tedious and error-prone so this saves a lot of typing and dumb bugs.
通过声明一个@property(并在.m文件中匹配@synthesize),您可以使用内存语义自动生成读写方法。大多数对象的经验法则是Retain,但是nsstring(例如)应该使用Copy。而单例和委托通常应该使用Assign。手工编写访问器是乏味和容易出错的,因此这节省了大量输入和愚蠢的错误。
Also, declaring a synthesized property lets you call an accessor method using dot notation like this:
另外,声明一个合成属性可以使用点符号调用访问器方法,如下所示:
self.otherObj = someOtherNewObject; // set it
MyOtherObject *thingee = self.otherObj; // get it
Instead of the normal, message-passing way:
而不是通常的、传递消息的方式:
[self setOtherObject:someOtherNewObject]; // set it
MyOtherObject *thingee = [self otherObj]; // get it
Behind the scenes you're really calling a method that looks like this:
在幕后,你实际上是在调用一个像这样的方法:
- (void) setOtherObj:(MyOtherObject *)anOtherObject {
if (otherObject == anOtherObject) {
return;
}
MyOtherObject *oldOtherObject = otherObject; // keep a reference to the old value for a second
otherObject = [anOtherObject retain]; // put the new value in
[oldOtherObject release]; // let go of the old object
} // set it
…or this
……或者这
- (MyOtherObject *) otherObject {
return otherObject;
} // get it
Total pain in the butt, right. Now do that for every ivar in the class. If you don't do it exactly right, you get a memory leak. Best to just let the compiler do the work.
屁股痛,对。现在对班上的每一个ivar都这样做。如果做得不好,就会出现内存泄漏。最好让编译器来完成这项工作。
I see that Number 1 doesn't have an ivar. Assuming that's not a typo, it's fine because the @property / @synthesize directives will declare an ivar for you as well, behind the scenes. I believe this is new for Mac OS X - Snow Leopard and iOS4.
我看到1号没有ivar。假设这不是一个拼写错误,这是可以的,因为在幕后,@property / @synthesize指令也会为您声明一个ivar。我相信这是Mac OS X - Snow Leopard和iOS4的新产品。
Number 3 does not have those accessors generated so you have to write them yourself. If you want your accessor methods to have side effects, you do your standard memory management dance, as shown above, then do whatever side work you need to, inside the accessor method. If you synthesize a property as well as write your own, then your version has priority.
数字3没有生成这些访问器,所以您必须自己编写它们。如果您希望您的访问器方法有副作用,那么您可以执行标准的内存管理舞蹈,如上所示,然后在访问器方法中执行您需要的任何边工作。如果您合成一个属性并编写自己的属性,那么您的版本具有优先级。
Did I cover everything?
我覆盖一切吗?
#2
16
Back in the old days you had ivars, and if you wanted to let some other class set or read them then you had to define a getter (i.e., -(NSString *)foo)
and a setter (i.e., -(void)setFoo:(NSString *)aFoo;
).
在以前,您有ivars,如果您想让其他类设置或读取它们,那么您必须定义一个getter(例如。, -(NSString *)foo和setter(即-(void)setFoo:(NSString *)aFoo;)。
What properties give you is the setter and getter for free (almost!) along with an ivar. So when you define a property now, you can set the atomicity (do you want to allow multiple setting actions from multiple threads, for instance), as well as assign/retain/copy semantics (that is, should the setter copy the new value or just save the current value - important if another class is trying to set your string property with a mutable string which might get changed later).
属性提供的是免费的setter和getter(几乎是!)以及ivar。所以当你现在定义一个属性,您可以设置原子性(你想允许多个设置从多个线程操作,例如),以及分配/保持/复制语义(也就是说,应该setter复制新值或者只是保存当前重要的价值——如果另一个类是试图用一个可变的字符串设置字符串属性可能会改变)。
This is what @synthesize
does. Many people leave the ivar name the same, but you can change it when you write your synthesize statement (i.e., @synthesize foo=_foo;
means make an ivar named _foo
for the property foo
, so if you want to read or write this property and you do not use self.foo
, you will have to use _foo = ...
- it just helps you catch direct references to the ivar if you wanted to only go through the setter and getter).
这就是@synthesize所做的。许多人都保留ivar名称,但是您可以在编写synthesize语句时更改它(例如,,@ synthesize foo = _foo;意思是为属性foo创建一个名为_foo的ivar,所以如果你想读或写这个属性,而不使用self。foo,你必须使用_foo =…-如果您只想通过setter和getter,它只帮助您捕获对ivar的直接引用)。
As of Xcode 4.6, you do not need to use the @synthesize
statement - the compiler will do it automatically and by default will prepend the ivar's name with _
.
在Xcode 4.6中,您不需要使用@synthesize语句——编译器会自动执行它,默认情况下,将以_为前缀将ivar的名称作为前缀。
#1
56
Number 1 differs from the other two by forward declaring the MyOtherObject class to minimize the amount of code seen by the compiler and linker and also potentially avoid circular references. If you do it this way remember to put the #import into the .m file.
第1号不同于另外两个,它向前声明MyOtherObject类,以最小化编译器和链接器看到的代码量,并可能避免循环引用。如果您这样做,请记住将#import放入.m文件中。
By declaring an @property, (and matching @synthesize in the .m) file, you auto-generate accessor methods with the memory semantics handled how you specify. The rule of thumb for most objects is Retain, but NSStrings, for instance should use Copy. Whereas Singletons and Delegates should usually use Assign. Hand-writing accessors is tedious and error-prone so this saves a lot of typing and dumb bugs.
通过声明一个@property(并在.m文件中匹配@synthesize),您可以使用内存语义自动生成读写方法。大多数对象的经验法则是Retain,但是nsstring(例如)应该使用Copy。而单例和委托通常应该使用Assign。手工编写访问器是乏味和容易出错的,因此这节省了大量输入和愚蠢的错误。
Also, declaring a synthesized property lets you call an accessor method using dot notation like this:
另外,声明一个合成属性可以使用点符号调用访问器方法,如下所示:
self.otherObj = someOtherNewObject; // set it
MyOtherObject *thingee = self.otherObj; // get it
Instead of the normal, message-passing way:
而不是通常的、传递消息的方式:
[self setOtherObject:someOtherNewObject]; // set it
MyOtherObject *thingee = [self otherObj]; // get it
Behind the scenes you're really calling a method that looks like this:
在幕后,你实际上是在调用一个像这样的方法:
- (void) setOtherObj:(MyOtherObject *)anOtherObject {
if (otherObject == anOtherObject) {
return;
}
MyOtherObject *oldOtherObject = otherObject; // keep a reference to the old value for a second
otherObject = [anOtherObject retain]; // put the new value in
[oldOtherObject release]; // let go of the old object
} // set it
…or this
……或者这
- (MyOtherObject *) otherObject {
return otherObject;
} // get it
Total pain in the butt, right. Now do that for every ivar in the class. If you don't do it exactly right, you get a memory leak. Best to just let the compiler do the work.
屁股痛,对。现在对班上的每一个ivar都这样做。如果做得不好,就会出现内存泄漏。最好让编译器来完成这项工作。
I see that Number 1 doesn't have an ivar. Assuming that's not a typo, it's fine because the @property / @synthesize directives will declare an ivar for you as well, behind the scenes. I believe this is new for Mac OS X - Snow Leopard and iOS4.
我看到1号没有ivar。假设这不是一个拼写错误,这是可以的,因为在幕后,@property / @synthesize指令也会为您声明一个ivar。我相信这是Mac OS X - Snow Leopard和iOS4的新产品。
Number 3 does not have those accessors generated so you have to write them yourself. If you want your accessor methods to have side effects, you do your standard memory management dance, as shown above, then do whatever side work you need to, inside the accessor method. If you synthesize a property as well as write your own, then your version has priority.
数字3没有生成这些访问器,所以您必须自己编写它们。如果您希望您的访问器方法有副作用,那么您可以执行标准的内存管理舞蹈,如上所示,然后在访问器方法中执行您需要的任何边工作。如果您合成一个属性并编写自己的属性,那么您的版本具有优先级。
Did I cover everything?
我覆盖一切吗?
#2
16
Back in the old days you had ivars, and if you wanted to let some other class set or read them then you had to define a getter (i.e., -(NSString *)foo)
and a setter (i.e., -(void)setFoo:(NSString *)aFoo;
).
在以前,您有ivars,如果您想让其他类设置或读取它们,那么您必须定义一个getter(例如。, -(NSString *)foo和setter(即-(void)setFoo:(NSString *)aFoo;)。
What properties give you is the setter and getter for free (almost!) along with an ivar. So when you define a property now, you can set the atomicity (do you want to allow multiple setting actions from multiple threads, for instance), as well as assign/retain/copy semantics (that is, should the setter copy the new value or just save the current value - important if another class is trying to set your string property with a mutable string which might get changed later).
属性提供的是免费的setter和getter(几乎是!)以及ivar。所以当你现在定义一个属性,您可以设置原子性(你想允许多个设置从多个线程操作,例如),以及分配/保持/复制语义(也就是说,应该setter复制新值或者只是保存当前重要的价值——如果另一个类是试图用一个可变的字符串设置字符串属性可能会改变)。
This is what @synthesize
does. Many people leave the ivar name the same, but you can change it when you write your synthesize statement (i.e., @synthesize foo=_foo;
means make an ivar named _foo
for the property foo
, so if you want to read or write this property and you do not use self.foo
, you will have to use _foo = ...
- it just helps you catch direct references to the ivar if you wanted to only go through the setter and getter).
这就是@synthesize所做的。许多人都保留ivar名称,但是您可以在编写synthesize语句时更改它(例如,,@ synthesize foo = _foo;意思是为属性foo创建一个名为_foo的ivar,所以如果你想读或写这个属性,而不使用self。foo,你必须使用_foo =…-如果您只想通过setter和getter,它只帮助您捕获对ivar的直接引用)。
As of Xcode 4.6, you do not need to use the @synthesize
statement - the compiler will do it automatically and by default will prepend the ivar's name with _
.
在Xcode 4.6中,您不需要使用@synthesize语句——编译器会自动执行它,默认情况下,将以_为前缀将ivar的名称作为前缀。