“属性”(property)有两大概念:ivar(实例变量)、存取方法(access method=getter),即@property = ivar + getter + setter。
例如下面的这个类:
@interface WBTextView :UITextView
@property (nonatomic,copy)NSString *placehold;
@property (nonatomic,copy)UIColor *placeholdColor;
@end
类完成属性的定以后,编译器会自动编写访问这些属性的方法(自动合成autosynthesis),上述代码写出来的类等效与下面的代码:
@interface WBTextView :UITextView
- (NSString *)placehold;
-(void)setPlacehold:(NSString *)placehold;
-(UIColor *)placeholdColor;
-(void)setPlaceholdColor:(UIColor *)placeholdColor;
@end
大家可能会想,编译器是如何实现该功能。原理如下:
1)OBJC_IVAR_$类名$属性名称 :该属性的“偏移量” (offset),这个偏移量是“硬编码” (hardcode),表示
该变量距离存放对象的内存区域的起始地址有多远。
2)setter与getter方法对应的实现函数
3)ivar_list :成员变量列表
4)method_list :方法列表
5)prop_list :属性列表
也就是说我们每次在增加一个属性,系统都会在ivar_list中添加一个成员变量的描述,在method_list中
增加setter与getter方法的描述,在属性列表中增加一个属性的描述,然后计算该属性在对象中的偏移量,
然后给出setter与getter方法对应的实现,在setter方法中从偏移量的位置开始赋值,在getter方法中从
偏移量开始取值,为了能够读取正确字节数,系统对象偏移量的指针类型进行了类型强转.
虽说系统自带的自动合成(autosynthesis)给我们带来很多方便,但有时一不小心就有可能导致错误。
@import Foundation;
@interface WBTextView :UITextView
@property (nonatomic,copy)NSString *placehold;
@end
-(instancetype)init
{
self = [superinitWithFrame:frame];
if (self) {
_placeholde = @"jasonjwl";
}
returnself;
}
-(NSString *)placehold
{
return _placehold;
}
-(void)setPlacehold:(NSString *)placehold
{
_placehold = [placehold copy];
}
上面的代码不能通过编译,因为当你同时重写setter和getter时,系统不会生成ivar变量。
那什么情况下,不会autosynthesis?
1.同时重写了setter和getter时重写了只读属性的getter时
2.使用了@dynamic时
3.在 @protocol 中定义的所有属性
4.在 category 中定义的所有属性
5.重载的属性
感谢程序猿的提供《招聘一个靠谱的 iOS》—参考答案(上)