1.历史由来
在 iOS5之前,属性的正常写法需要三个步骤
- 成员变量
- @property
- @synthesize
实例代码
@interface ViewController () {
// 1.声明成员变量
NSString *name;
}
// 2.用@property
@property(nonatomic, copy)NSString *name;
@end
@implementation ViewController
// 3.最后在@implementation中用synthesize生成set方法
@synthesize name;
如果漏写了 @synthesize,则编译时会有警告
Autosynthesized property 'name' will use synthesized instance variable
'_name', not existing instance variable 'name'
在iOS5之后,苹果推出一个新机制,@property声明的属性默认会生成一个_类型的成员变量,同时也会生成setter/getter方法。
其实,发生这种状况根本原因是苹果将默认编译器从GCC转换为LLVM(low level virtual machine),才不再需要为属性声明实例变量了。
更换为LLVM之后,编译器在编译过程中发现没有新的实例变量后,就会生成一个下划线开头的实例变量。因此现在我们不必在声明一个实例变量。(注意:是不必要,不是不可以)
在.m文件中,编译器也会自动的生成一个实例变量_name。那么在.m文件中可以直接的使用_name实例变量,也可以通过属性self.name都是一样的。
注意这里的self.myString其实是调用的myString属性的setter/getter方法。这与C++中点的使用是有区别的,C++中的点可以直接访问成员变量(也就是实例变量)。
实战检验
- 直接生成成员变量
@interface ViewController () {
NSString *name;
}
@end
在这段代码里面只是声明了一个成员变量,并没有setter/getter方法。所以访问成员变量时,可以直接访问name,也可以像C++一样用self->name来访问。
// 访问1
name = @"韩雪";
NSLog(@"name = %@",name);
// 访问e2
self->name = @"孙悟空";
NSLog(@"name = %@",self->name);
打印结果
但绝对不能用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成员变量的形式。
@synthesize还有一个作用,可以指定与属性对应的实例变量,例如@synthesize name = xxx;
那么self.name其实是操作的实例变量xxx,而非_name了。
- 实例代码1
@synthesize name = myName;
self.name = @"韩雪";
NSLog(@"_name = %@",self->_name);
打印结果
- 实例代码2
@synthesize name = myName;
self.name = @"韩雪";
NSLog(@"_myName = %@",self->myName);
打印结果
2.@dynamic与@synthesize的区别
@dynamic
dynamic告诉编译器,不自动生成getter/setter方法。
- 实例代码
@interface ViewController ()
@property(nonatomic, copy)NSString *name;
@end
@implementation ViewController
@dynamic name;
- (void)viewDidLoad {
[super viewDidLoad];
self.name = @"韩雪";
NSLog(@"name = %@",self.name);
}
@end
运行结果 - 直接崩溃,报方法找不到的错误。
@synthesize
添加@synthesize,让编译器自动生成getter/setter方法。
当有自定义的存或取方法时,自定义会屏蔽自动生成的getter/setter方法。
- 实例代码
@synthesize name = _myName;
- (void)viewDidLoad {
[super viewDidLoad];
self.name = @"韩雪";
NSLog(@"name = %@",self.name);
}
// 自定义 set 方法
- (void)setName:(NSString *)name {
_myName = @"孙悟空";
}
// 自定义 get方法
- (NSString *)name {
return _myName;
}
打印结果
3.总结
成员变量
1. 成员变量的默认修饰是@protected。
2. 成员变量不会自动生成set和get方法,需要自己手动实现。
3. 成员变量不能用点语法调用,因为没有set和get方法,只能使用->调用。
属性
1. 属性的默认修饰是@protected。
2. 属性会自动生成set和get方法。
3. 属性用点语法调用,点语法实际上调用的是set和get方法。