属性
使用属性
在定义类时有一个属性的概念。我们使用关键字@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];
: 赋值,同时引用计数器加 1self->foo = [value copy];
: 对象拷贝(必须满足协议NSCopying
)
在有垃圾收集器的环境下,retain
同assign
没有区别,但是可以加上__weak
或者__strong
。
@property(copy,getter=getS,setter=setF:) __weak NSString* s; // 复杂声明
注意不要忘记 setter 的冒号 : 。
2 评论
精彩啊 对了 你有没有从事MAC 或iphone的项目开发啊 现在
目前有在做一个 iphone 的程序,不过也只是刚刚开始学,呵呵