@property、@synthesize和@dynamic

903 阅读3分钟

完成属性定义后,编译器会自动编写访问这些属性所需的方法,此过程叫做“自动合成”(autosynthesis)。需要强调的是,这个过程由编译 器在编译期执行,所以编辑器里看不到这些“合成方法”(synthesized method)的源代码。除了生成方法代码 getter、setter 之外,编译器还要自动向类中添加适当类型的实例变量,并且在属性名前面加下划线,以此作为实例变量的名字。

我们每次在增加一个属性,系统都会在 ivar_list 中添加一个成员变量的描述,在 method_list 中增加 setter 与 getter 方法的描述,在属性列表中增加一个属性的描述,然后计算该属性在对象中的偏移量,然后给出 setter 与 getter 方法对应的实现,在 setter 方法中从偏移量的位置开始赋值,在 getter 方法中从偏移量开始取值,为了能够读取正确字节数,系统对象偏移量的指针类型进行了类型强转.

@property

@property(nonatomic,copy)NSString *name; 相当于是

1.声明了:

(NSString *)name;  
(void)setName:(NSString *)str;
  1. 生成成员变量 _name

  2. 实现了:

    (NSString *)name;
    (void)setName:(NSString *)str;

  • 对于@property的参数 如果是使用@property(nonatomic,copy,getter=familyName)NSString *name; 则是相当于get方法为:
(NSString *)familyName;
而实现的时候则为:
(NSString *)familyName{
return name;
}

readwrite: 产生setter\getter方法(默认参数)
readonly: 只产生简单的getter,没有setter。
assign: 默认类型,setter方法直接赋值,而不进行retain操作(默认参数)
retain: setter方法对参数进行release旧值,再retain新值。
copy: setter方法进行Copy操作,与retain一样
nonatomic: 禁止多线程,变量保护,提高性能
atomic:原子性的访问方法(默认参数)

@synthesize

先去访问同名变量; 如果没有定义NSString *_name; 相当定义了先NSString *_name; 再实现了:

(NSString *)name{
return _name;
}
(void)setName:(NSString *)str{
if(_name != str){
[_name release];
_name = [str retain];
}
}

自动合成没有任何内存的含义,所以它根本没有连接到ARC。

当然,如果自己本身就已经实现了

(NSString *)name;
(void)setName:(NSString *)str;

这两个方法,那么系统就不再实现了。 对于现在,如果不使用
@synthesize name = _name; 也默认是使用@synthesize name = _name; @synthesize name; 如果使用的是@synthesize name; 那么对于上面的变量则为生成的是name而不是_name; 相当于是

(NSString *)name{
return name;
}
(void)setName:(NSString *)str{
if(name != str){
[name release];
name = [str retain];
}
}

@synthesize name = testName; 如果使用的是@synthesize name = testName; 则对于上面的变量则为生成的是testName而不是name,方法也对应改变,

总之:定义的变量是根据@synthesize name = xx;来定的。

注意:属性的setter方法和getter方法是不能同时进行重写的,这是因为,一旦你同时重写了这两个方法,那么系统就不会帮你生成这个成员变量了,所以会报错

@dynamic

@dynamic 告诉编译器:属性的 setter 与 getter 方法由用户自己实现,不自动生成。假如一个属性被声明为 @dynamic var,而且你没有提供 @setter方法和 @getter 方法,编译的时候没问题,但是当程序运行到 instance.var = someVar,由于缺 setter 方法会导致程序崩溃;或者当运行到 someVar = var 时,由于缺 getter 方法同样会导致崩溃。编译时没问题,运行时才执行相应的方法,这就是所谓的动态绑定。

如果某属性已经在某处实现了自己的 setter/getter ,可以使用 @dynamic 来阻止 @synthesize 自动生成新的 setter/getter 覆盖。

注意

一种情形需要使用 @synthesize ,就是当在 protocol 中声明并实现属性时。协议中声明的属性不会自动生成setter和getter,[UIApplicationDelegate window] 就是个典型的例子。