原文地址:http://www.devbean.info/2011/04/from_cpp_to_objc_21/
属性
使用属性
在定义类时有一个属性的概念。我们使用关键字 @property 来标记一个属性,告诉编译器自动生成访问代码。属性的主要意义在于节省开发代码量。
访问属性的语法比方法调用简单,因此即使我们需要编写代码时,我们也可以使用属性。访问属性同方法调用的性能是一样的,因为属性的使用在编译期实际就是换成了方法调用。大多数时候,属性用于封装成员变量。但是,我们也可以提供一个“假”的属性,看似是访问一个数据成员,但实际不是;换句话说,看起来像是从对象外部调用一个属性,但实际上其实现要比一个值的管理操作要复杂得多。
属性的描述
对属性的描述实际上是要告诉编译器如何生成访问器的代码:
- 属性从外界是只读的吗?
- 如果数据成员是原生类型,可选余地不大;如果是对象,那么使用 copy 封装的话,是要用强引用还是弱引用?
- 属性是线程安全的吗?
- 访问器的名字是什么?
- 属性应该关联到哪一个数据成员?
- 应该自动生成哪一个访问器,哪一个则留给开发人员?
我们需要两个步骤来回答这些问题:
- 在类的 @interface 块中,属性的声明需要提供附属参数;
- 在类的 @implementation 块中,访问器可以隐式生成,也可以指定一个实现。
属性访问器是有严格规定的:getter 要求必须返回所期望的类型(或者是相容类型);setter 必须返回 void,并且只能有一个期望类型的参数。访问器的名字也是规定好的:对于数据 foo,getter 的名字是 foo,setter 的名字是 setFoo:。当然,我们也可以指定自定义的名字,但是不同于前面所说的键值对编码,这个名字必须在编译期确定,因为属性的使用被设计成要和方法的直接调用一样的性能。因此,如果类型是不相容的,是不会有装箱机制的。
以下是带有注释的例子,先来有一个大体的了解。
@interface class Car : NSObject { NSString* registration; Person* driver; } // registration 是只读的,使用 copy 设置 @property NSString* (readonly, copy) registration; // driver 使用弱引用(没有 retain),可以被修改 @property Person* (assign) driver; @end ... @implementation // 开发者没有提供,由编译期生成 registration 的代码 @synthesize registration; // 开发者提供了 driver 的 getter/setter 实现 @dynamic driver; // 该方法将作为 @dynamic driver 的 getter -(Person*) driver { ... } // 该方法将作为 @dynamic driver 的 setter -(void) setDriver:(Person*)value { ... } @end
属性的参数
属性的声明使用一下模板:
@property type name;
或者
@property(attributes) type name;
如果没有给出属性的参数,那么将使用默认值;否则将使用给出的参数值。这些参数值可以是:
- readwrite(默认)或者 readonly:设置属性是可读写的(拥有 getter/setter)或是只读的(只有 getter);
- assign(默认),retain 或 copy:设置属性的存储方式;
- nonatomic:不生成线程安全的代码,默认是生成的(没有 atomic 关键字);
- getter=…,setter=…:改变访问器默认的名字。
对于 setter,默认行为是 assign;retain 或者 copy 用于数据成员被修改时的操作。在一个 -(void) setFoo:(Foo*)value 方法中,会因此生成三种不同的语句:
- self->foo = value ; // 简单赋值
- self->foo = [value retain]; // 赋值,同时引用计数器加 1
- self->foo = [value copy]; // 对象拷贝(必须满足协议 NSCopying)
在有垃圾收集器的环境下,retain 同 assign 没有区别,但是可以加上 __weak 或者 __strong。
@property(copy,getter=getS,setter=setF:) __weak NSString* s; // 复杂声明
注意不要忘记 setter 的冒号 : 。
浙公网安备 33010602011771号