文章结构
- 历史由来
- @dynamic与@synthesize的区别
一、历史由来:
接触iOS
的人都知道,@property
声明的属性默认会生成一个_类型的成员变量,同时也会生成setter/getter
方法。
但这只是在iOS5
之后,苹果推出的一个新机制。看老代码时,经常看到一个大括号里面定义了成员变量,同时用了@property
声明,而且还在@implementation
中使用@synthesize
方法。
如下:
@interface ViewController (){
// 1.声明成员变量
NSString *myString;
}
//2.在用@property
@property(nonatomic, copy) NSString *myString;
@end
@implementation ViewController
//3.最后在@implementation中用synthesize生成set方法
@synthesize myString;
@end
其实,发生这种状况根本原因是苹果将默认编译器从GCC
转换为LLVM(low level virtual machine)
,才不再需要为属性声明实例变量了。
在没有更改之前,属性的正常写法需要成员变量+ @property + @synthesize 成员变量
三个步骤。
如果我们只写成员变量+ @property
:
@interface GBViewController :UIViewController{
NSString *myString;
}
@property (nonatomic, strong) NSString *myString;
@end
编译时会报警告:
Autosynthesized property '�myString' will use synthesized instance variable
'_myString', not existing instance variable 'myString'
但更换为LLVM
之后,编译器在编译过程中发现没有新的实例变量后,就会生成一个下划线开头的实例变量。因此现在我们不必在声明一个实例变量。(注意:是不必要,不是不可以)
当然我们也熟知,@property
声明的属性不仅仅默认给我们生成一个_
类型的成员变量,同时也会生成setter/getter
方法。
在.m文件中,编译器也会自动的生成一个实例变量_myString
。那么在.m文件中可以直接的使用_myString
实例变量,也可以通过属性self.myString
.都是一样的。
注意这里的self.myString
其实是调用的myString
属性的setter/getter
方法。这与C++
中点的使用是有区别的,C++
中的点可以直接访问成员变量(也就是实例变量)。
例如在oc中有如下代码
@interface MyViewController :UIViewController{
NSString *name;
}
@end
在这段代码里面只是声明了一个成员变量,并没有setter/getter
方法。所以访问成员变量时,可以直接访问name
,也可以像C++
一样用self->name
来访问,但绝对不能用self.name
来访问。
扩展:很多人觉得OC中的点语法比较奇怪,实际是OC设计人员有意为之。
- 点表达式
(.)
看起来与C语言中的结构体访问以及java语言汇总的对象访问有点类似,如果点表达式出现在等号=
左边,调用该属性名称的setter
方法。如果点表达式出现在=
右边,调用该属性名称的getter
方法。- OC中点表达式(.)其实就是调用对象的
setter
和getter
方法的一种快捷方式,self.myString = @"张三";
实际就是[self setmyString:@"张三"]
;
首先我们要明白,@synthesize
生成了setter/getter
方法。
虽然现在直接使用@property
时,编译器会自动为你生成以下划线开头的实例变量_myString
,不需要自己手动再去写实例变量。而且也不在.m文件中通过@synthesize myString
;生成setter/getter
方法。但在看老代码的时候,我们依旧可以看到有人使用成员变量+ @synthesize
成员变量的形式。
那么问题来了:
我们能否认为新编译器LLVM下
的@property == 老编译器GCC的 成员变量+ @property + @synthesize
成员变量呢?
答案是否定的。
因为成员变量+ @property + @synthesize
成员变量的形式,编译器不会帮我们生成成员变量,因此不会操作成员变量了;
同时@synthesize
还有一个作用,可以指定与属性对应的实例变量,
例如@synthesize myString = xxx
;
那么self.myString
其实是操作的实例变量xxx
,而非_String
了。
二、@dynamic与@synthesize的区别
dynamic
告诉编译器,不自动生成getter/setter
方法,避免编译期间产生警告
然后由自己实现存取方法,或存取方法在运行时动态创建绑定。
如下:
synthesize
编译器期间,让编译器自动生成getter/setter
方法。
当有自定义的存或取方法时,自定义会屏蔽自动生成该方法