以前:
在老版本的Objective-C
语言中,我们需要同时声明属性和底层实例变量,那时,属性是Objective-C语言的一个新的机制,并且要求你必须声明与之对应的实例变量,例如:
@interface MyViewController :UIViewController
{
__strong UIButton *_myButton; //实例变量
}
@property (nonatomic, retain) UIButton *myButton; //属性
@end
后来,苹果将默认编译器从GCC转换为LLVM(low level virtual machine),从此不再需要为属性声明实例变量了。如果LLVM发现一个没有匹配实例变量的属性,它将自动创建一个以下划线开头的实例变量。
现在:
1. @synthesize的作用(1):让编译器为你自动生成setter与getter方法。
如果使用了属性的话,那么编译器就会自动编写访问属性所需的方法,此过程叫做“自动合成”( auto synthesis)。需要强调的是,这个过程由编译器在编译期执行,所以编辑器里看不到这些“合成方法” 的源代码
@interface CYLPerson : NSObject
//@property = ivar + getter + setter; (ivar = 实例变量 = 成员变量)
//会生成两个实例变量,其名称分别为 _firstName与_lastName
@property NSString *firstName;
@property NSString *lastName;
@end
2. @synthesize 的作用(2):可以指定与属性对应的实例变量。
例如 @synthesize myButton = xxx;那么self.myButton其实是操作的实例变量xxx,而不是_myButton了。这样写了之后,那么编译器会自动生成myButton的实例变量,以及相应的getter和setter方法。注意:_myButton这个实例变量是不存在的,因为自动生成的实例变量为myButton而不是_myButton,所以现在@synthesize的作用就相当于指定实例变量;
如果.m文件中写了@synthesize myButton,那么生成的实例变量就是myButton;如果没写@synthesize myButton;那么生成的实例变量就是_myButton。
问题:
1. 什么情况下不会autosynthesis(自动合成)?
- 同时重写了setter和getter时
- 重写了只读属性的getter时
- 使用了@dynamic时
- 在 @protocol 中定义的所有属性
- 在 category 中定义的所有属性
- 重载的属性
- 当你在子类中重载了父类中的属性,你必须 使用@synthesize来手动合成ivar。
除了后三条,对其他几个我们可以总结出一个规律:当你想手动管理@property的所有内容时,你就会尝试通过实现@property的所有“存取方法”(the accessor methods),或者使用@dynamic来达到这个目的,这时编译器就会认为你打算手动管理@property,于是编译器就禁用了autosynthesis(自动合成)。
举例说明:
当你同时重写了setter和getter时,系统就不会生成ivar(实例变量/成员变量)。
这时候有两种选择:
- 要么如第14行:手动创建ivar
- 要么如第17行:使用@synthesize foo = _foo; ,关联@property与ivar。
2. @synthesize和@dynamic分别有什么作用?
1)@property有两个对应的词,一个是@synthesize,一个是@dynamic。如果@synthesize和@dynamic都没写,那么默认的就是@syntheszie var = _var;
2)@synthesize的语义是如果你没有手动实现setter方法和getter方法,那么编译器会自动为你加上这两个方法。
3)@dynamic告诉编译器:属性的setter与getter方法由用户自己实现,不自动生成。(当然对于readonly的属性只需提供getter即可)。
假如一个属性被声明为@dynamic var,然后你没有提供@setter方法和@getter方法,编译的时候没问题,但是当程序运行到instance.var = someVar,
由于缺setter方法会导致程序崩溃;或者当运行到 someVar = var时,由于缺getter方法同样会导致崩溃。编译时没问题,运行时才执行相应的方法,这就是所谓的动态绑定。