Objective-C属性详解
理解属性
谈到属性,人们总是说这个对象的属性指向一个什么对象,把那个属性设置为一个值,等等。这样的说法,让人觉得属性是一个具体的事物,是对象的一部分。
但是,个人认为,属性其实是一种基于面向对象编程的机制
。通过这个机制,我们得以将数据封装在对象内,这里的封装包括存入和获取数据的动作
,以及存放的地点
。
没错,上面提到的动作和地点分别暗指存取方法
和实例变量
,它们支持着属性机制。两者缺一不可,没有它们,属性机制也就不能正常运行。
@property指令
关于@property
指令的具体作用,苹果文档也没有一个明确统一的说法。但是经过试验和总结,它有如下主要功能。
以@property NSString *word;
为例:
- 定义了名为
_word
的的实例变量。 - 声明和实现了名为
- (NSString *)word
和- (void)setWord:
的存取方法。
也就是说,利用@property
声明属性,就构建由实例变量和存取方法支持的属性机制。
实例变量
作为保存数据的地点
,实例变量对于对象来说是不可或缺的。除了使用@property指令自动对其进行定义之外,还可以手动定义实例变量,例如:
@interface Test : NSObject {
NSString *_word; // 定义一个实例变量_word
}
@end
这样定义出来的实例变量同使用@prperty定义的效果完全相同。
存取方法
有了保存数据的地点,存放和获取数据的手段也必不可少。除了使用@property自动实现默认的存取方法以外,也可以手动声明和实现存取方法。例如:
@interface Test : NSObject {
NSString *_word; // 定义一个实例变量_word
}
- (void)setWord:(NSString *)w;
- (NSString *)word;
@end
// 以上是interface,以下是implementation
@implementation Test
// 实现_word的默认存取方法
- (void)setWord:(NSString *)w
{
_word = w;
}
- (NSString *)word
{
return _word;
}
@end
事实上,通过@property所实现的默认存取方法同上面的实现一致。(除了在对属性使用atomic
限定词的情况下,稍后会解释)
架空属性
上面提到过,属性机制由实例变量和存取方法支持,二者缺一不可。但是,它的灵活之处在于,属性的实例变量和存取方法之间也存在依赖关系:存取方法之中至少有一个必须通过@property自动实现,否则,实例变量将不会被自动定义。
也就是说,如果同时手动实现了存取方法(在只读情况下实现了取方法),那么就没有实例变量可用了。例如:
@interface Test : NSObject
@property NSString *word;
@end
// 以上是interface,以下是implementation
@implementation Test
// 实现_word的默认存取方法
- (void)setWord:(NSString *)w
{
_word = w; // 报错
}
- (NSString *)word
{
return _word; // 报错
}
@end
上面的代码,word的存取方法中引用_word
的地方会报错,提示实例变量_word不存在
。这时,编译器会认为你想架空属性机制,所以不再自动定义实例变量。
之所以有这样的设定,是因为通常情况下,默认的属性机制可以满足我们的正常使用;但是,在某些情况下例外,例如一个属性完全依赖于另一个属性,以至于它们存放数据的地点都是同一个
,所以,它们共用一个实例变量即可。
@synthesize指令
在一些较早的书籍中,经常出现在.h文件
中使用@property定义属性,然后在.m文件
中使用@synthesize合成属性
的情况出现,书上解释为:合成相应属性的实例变量和存取方法。
但是,截至本文写作之时,利用@property声明属性之后,不论是否使用@synthesize都会自动定义实例变量以及实现存取方法。这样看来,@synthesize的功能稍显多余。
但是,除了这些重复功能之外,@synthesize还有一些用法,值得注意。
-
手动定义实例变量
。在同时实现存取方法的情况下,默认实例变量不在自动定义。这时,使用@synthesize可以定义一个可用的实例变量。 -
修改实例变量的名称
。默认情况下,实例变量的名称是_属性名
。通过@synthesize 属性名 = 新实例变量名
的形式,可以修改其名称。
注意: @synthesize必须和@property配套使用
。例如,如果没有使用@property,而是手动定义了实例变量,再用@synthesize实现存取方法,是不可以的。此时,只能手动实现存取方法。
属性特性
属性可以拥有一组特性,用来限定存取方法的行为,写在小括号里。例如:
@property (nonatomic, readonly, strong) NSString *word;
有三类:
-
多线程特性
:atomic / nonatomic。前者可以保证属性在通过多线程存取是不会发生错误。但注意,在使用atomic的情况下,不能再手动生成存取方法,因为它们的实现包含了线程管理的内容。一般都用nonatomic。 -
读写特性
:readonly / readwrite。前者只允许实现取方法。 -
内存管理特性
:又分为非ARC模式和ARC模式下。-
非ARC
-
retain
:限定指针类型的变量,指针所指向的对象的引用计数加1。 -
assign
:限定非指针和id类型的变量,不对引用计数进行操作。 -
copy
:限定指针类型的变量,复制接收copy消息的对象,并将变量指向这个新的对象。多用于防止可变类型的对象放生改变。
-
-
ARC
-
strong
:作用同非ARC模式下的retain。 -
weak
:限定指针类型的变量,作用同非ARC模式下的assign,但是,但变量所指向的对象被释放后,指针自动被设置为nil
。 -
assign
:限定非指针类型的变量,如int,float,结构体等基本数据类型。也可以用关键字unsafe_unretained
来表示。
-
-
网友评论