属性
使用属性
在定义类时有一个属性的概念。我们使用关键字@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 的程序,不过也只是刚刚开始学,呵呵