成员变量和属性的前世今生

目录:

1.简述编译器的变化对@property的影响;
2.实际使用中@property和成员变量+ @property + @synthesize 成员变量的区别
3.self.XXX,_XXX,self->XXX的区别;
4.Demo地址

历史由来:

接触iOS的人都知道,@property声明的属性默认会生成一个_类型的成员变量,同时也会生成setter/getter方法。
但这只是在iOS5之后,苹果推出的一个新机制。看老代码时,经常看到一个大括号里面定义了成员变量,同时用了@property声明,而且还在@implementation中使用@synthesize方法。
如下:

1
2
3
4
5
6
7
8
9
10
11
12
13
@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

1
2
3
4
5
6
@interface GBViewController :UIViewController
{
    NSString *myString;
}
@property (nonatomic, strong) NSString *myString;
@end

编译时会报警告:

property 'myString' will use synthesized instance variable '_myString', not existing instance variable 'myString''```
1
2
3
4
5
6
7
8
9
但更换为LLVM之后,编译器在编译过程中发现没有新的实例变量后,就会生成一个下划线开头的实例变量。因此现在我们不必在声明一个实例变量。(**注意:是不必要,不是不可以**)
当然我们也熟知,`@property`声明的属性不仅仅默认给我们生成一个_类型的成员变量,同时也会生成`setter/getter`方法。
在`.m`文件中,编译器也会自动的生成一个实例变量`_XXX`。那么在.m文件中可以直接的使用`_XXX`实例变量,也可以通过属性`self. XXX`。
只是我们需要注意这里的`self.XXX`实际是调用`XXX`属性的`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中点表达式(.)其实就是调用对象的settergetter方法的一种快捷方式,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了。

Demo中会有非常详细的说明,欢迎下载和start。

写在最后

技术学习绝不能孤胆英雄独闯天涯,而应在一群人的交流碰撞,享受智慧火花的狂欢。
希望我的文章能成为你的盛宴,也渴望你的建议能成为我的大餐。