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

enn*_*ler 81 properties objective-c instance-variables

在objective-c中使用ivars和属性的这三种方式之间的语义差异是什么?

1.

@class MyOtherObject; 
@interface MyObject {
}
@property (nonatomic, retain) MyOtherObject *otherObj;
Run Code Online (Sandbox Code Playgroud)

2.

#import "MyOtherObject.h"
@interface MyObject {
    MyOtherObject *otherObj;
}
@property (nonatomic, retain) MyOtherObject *otherObj;
Run Code Online (Sandbox Code Playgroud)

3.

#import "MyOtherObject.h"
@interface MyObject {
    MyOtherObject *otherObj;
}
Run Code Online (Sandbox Code Playgroud)

wil*_*lc2 56

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

通过声明@property(并在.m中匹配@synthesize)文件,您可以自动生成访问器方法,并按照您指定的方式处理内存语义.大多数对象的经验法则是Retain,但NSStrings例如应该使用Copy.单身人士和代表通常应该使用Assign.手写访问器繁琐且容易出错,因此可以节省大量的输入和愚蠢的错误.

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

self.otherObj = someOtherNewObject; // set it  
MyOtherObject *thingee = self.otherObj; // get it 
Run Code Online (Sandbox Code Playgroud)

而不是正常的消息传递方式:

[self setOtherObject:someOtherNewObject]; // set it
MyOtherObject *thingee = [self otherObj]; // get it 
Run Code Online (Sandbox Code Playgroud)

在幕后,你真的在​​调用一个看起来像这样的方法:

- (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
Run Code Online (Sandbox Code Playgroud)

…或这个

- (MyOtherObject *) otherObject {  
    return otherObject;
} // get it
Run Code Online (Sandbox Code Playgroud)

对接总疼痛,对.现在为班上的每一个ivar做这个.如果你不完全正确,就会出现内存泄漏.最好让编译器完成工作.

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

3号没有生成那些访问器,所以你必须自己编写它们.如果你希望你的访问器方法有副作用,你可以进行标准的内存管理跳舞,如上所示,然后在访问器方法中做你需要的任何工作.如果您合成属性以及编写自己的属性,那么您的版本具有优先权.

我是否涵盖了一切?

  • 关于点符号的一点点的答案很好.您无需合成属性即可将其用于点表示法.实际上,您根本不需要声明属性.只要你有一个声明的setter和getter(例如`setFoo:`和`foo`)你就可以使用点符号. (3认同)

Dav*_*d H 17

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

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

这是做什么的@synthesize.很多人都把ivar的名字保持不变,但是你可以在编写合成语句时更改它(即,@synthesize foo=_foo;意味着_foo为该属性命名为ivar foo,所以如果你想读或写这个属性而你不使用self.foo,你会必须使用_foo = ...- 它只是帮助你直接引用ivar,如果你只想通过setter和getter).

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

  • 您可以保证获得一个有效的整个对象 - getter将不会返回正在被解除分配的对象 - 但如果另一个线程正在使用setter,您可以从之前或之后获取该值.指定必须在getter和setter之外处理.换句话说,在getter或setter操作中没有线程会被中断_但是操作的顺序不是(不能在此级别,AFAIK)定义的. (2认同)