82

这 3 种在 Objective-C 中使用 ivars 和属性的方式在语义上有什么区别?

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

2 回答 2

57

数字 1与其他两个不同,它通过前向声明 MyOtherObject 类来最小化编译器和链接器看到的代码量,并且还可能避免循环引用。如果您这样做,请记住将#import 放入 .m 文件中。

通过声明@property(并在.m 中匹配@synthesize)文件,您可以自动生成访问器方法,并按照您指定的方式处理内存语义。大多数对象的经验法则是保留,但 NSStrings,例如应该使用复制。而单身人士和委托人通常应该使用分配。手写访问器乏味且容易出错,因此可以节省大量打字和愚蠢的错误。

此外,声明合成属性允许您使用点符号调用访问器方法,如下所示:

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执行此操作。如果您没有完全正确地执行此操作,则会出现内存泄漏。最好让编译器完成工作。

我看到1 号没有 ivar。假设这不是错字,那很好,因为 @property / @synthesize 指令也会在幕后为您声明一个 ivar。我相信这对于 Mac OS X - Snow Leopard 和 iOS4 来说是新的。

3 号没有生成这些访问器,因此您必须自己编写它们。如果您希望访问器方法具有副作用,请执行标准的内存管理舞蹈,如上所示,然后在访问器方法中执行您需要的任何辅助工作。如果您综合属性并编写自己的属性,则您的版本具有优先权。

我涵盖了所有内容吗?

于 2010-11-13T15:21:37.623 回答
17

回到过去,你有 ivars,如果你想让其他类设置或读取它们,那么你必须定义一个 getter(即,-(NSString *)foo)和一个 setter(即,-(void)setFoo:(NSString *)aFoo;)。

什么属性给你的是免费的(几乎!)setter 和 getter 以及一个 ivar。因此,当您现在定义一个属性时,您可以设置原子性(例如,您是否希望允许来自多个线程的多个设置操作)以及分配/保留/复制语义(即,setter 是否应该复制新值或者只是保存当前值 - 如果另一个类试图使用可变字符串设置您的字符串属性,该字符串可能稍后会更改)。

这就是这样@synthesize做的。很多人保持 ivar 名称不变,但是您可以在编写 synthesize 语句时更改它(即,@synthesize foo=_foo;意味着_foo为该属性创建一个命名的 ivar foo,因此如果您想读取或写入此属性并且您不使用self.foo,您将必须使用_foo = ...- 如果您只想通过 setter 和 getter,它只会帮助您捕获对 ivar 的直接引用)。

从 Xcode 4.6 开始,您不需要使用该@synthesize语句 - 编译器会自动执行此操作,并且默认情况下会在 ivar 的名称前加上_.

于 2012-08-05T19:49:12.413 回答