Objective-C中的ivars和属性有什么区别

时间:2010-11-13 13:46:45

标签: objective-c properties instance-variables

在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;
}

2 个答案:

答案 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的名称。