在Objective-C中使用ivars和属性的这3种方法之间的语义差异是什么?
1
@class MyOtherObject;
@interface MyObject {
}
@property (nonatomic, retain) MyOtherObject *otherObj;
2
#import "MyOtherObject.h"
@interface MyObject {
MyOtherObject *otherObj;
}
@property (nonatomic, retain) MyOtherObject *otherObj;
3
#import "MyOtherObject.h"
@interface MyObject {
MyOtherObject *otherObj;
}
答案 0 :(得分:56)
Number 1 与其他两个不同,前向声明MyOtherObject类以最小化编译器和链接器看到的代码量,并且还可能避免循环引用。如果这样做,请记住将#import放入.m文件中。
通过声明@property,(并在.m中匹配@synthesize)文件,您可以自动生成访问器方法,并按照您指定的方式处理内存语义。大多数对象的经验法则是Retain,但NSStrings例如应该使用Copy。单身人士和代表通常应该使用Assign。手写访问器繁琐且容易出错,因此可以节省大量的输入和愚蠢的错误。
此外,声明合成属性允许您使用点符号调用访问器方法,如下所示:
self.otherObj = someOtherNewObject; // set it
MyOtherObject *thingee = self.otherObj; // get it
而不是正常的,消息传递方式:
[self setOtherObject:someOtherNewObject]; // set it
MyOtherObject *thingee = [self otherObj]; // get it
在幕后,你真的在调用一个看起来像这样的方法:
- (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
......或者
- (MyOtherObject *) otherObject {
return otherObject;
} // get it
臀部总疼痛,对。现在为类中的每个ivar 执行此操作。如果你不完全正确,就会出现内存泄漏。最好让编译器完成工作。
我看到 Number 1 没有ivar。假设这不是拼写错误,那很好,因为@property / @synthesize指令也会在幕后为你声明一个ivar。 我相信这对Mac OS X来说是新的 - Snow Leopard和iOS4。
Number 3 没有生成这些访问者,因此您必须自己编写。如果你希望你的访问器方法有副作用,你可以进行标准的内存管理跳舞,如上所示,然后在访问器方法中做你需要的任何工作。如果您合成了一个属性以及编写自己的,那么您的版本具有优先权。
我是否涵盖了所有内容?
答案 1 :(得分:16)
回到过去你有ivars,如果你想让其他类设置或阅读它们,那么你必须定义一个getter(即-(NSString *)foo)
和一个setter(即{{1} })。
什么属性给你的是免费的setter和getter(差不多!)以及ivar。因此,当您现在定义属性时,您可以设置原子性(例如,您是否允许来自多个线程的多个设置操作),以及分配/保留/复制语义(也就是说,如果setter复制新值或者只保存当前值 - 如果另一个类试图用可变字符串设置你的字符串属性很重要,以后可能会改变它。)
这是-(void)setFoo:(NSString *)aFoo;
的作用。许多人都将ivar名称保持不变,但您可以在编写合成语句时更改它(即,@synthesize
表示为属性@synthesize foo=_foo;
创建名为_foo
的ivar,所以如果你想要读取或写入此属性并且不使用foo
,您将不得不使用self.foo
- 它只是帮助您捕获对ivar的直接引用,如果您只想通过setter和getter )。
从Xcode 4.6开始,您不需要使用_foo = ...
语句 - 编译器会自动执行此操作,默认情况下将使用@synthesize
添加ivar的名称。