前言:点语法的由来

属性的演变
   1 最基本的方式
   自己定义实例变量    自己声明和定义 setter和getter方法
   支持点语法
   2 为了简化getter  setter函数声明 提供了一个语法
   @property   属性的类型     属性名;
   为了简化实现 提供了
   /* 实例变量的名字和 属性名相同 */
   @synthesize  属性名;
  * 实例变量的名字和 属性名不相同 */
   @synthesize  属性名=_实例变量名;
  3 新的演变
   IOS5开始可以不定义实例变量  自动生成 _属性名

   IOS6 开始就不用再写 @synthesize (但是,如果在.m文件里面重写属性的getter和setter方法的话@synthesize 属性 _属性,这个必须要写,否则的话,会报错)
   /* 这一句是必不可少 */
   @property  属性的类型    属性的名字;

因为编译器会自动为你生成以下划线开头的实例变量_属性名,不需要自己手动再去写实例变量。而且也不需要在.m文件中写@synthesize myButton;也会自动为你生成setter,getter方法。@synthesize的作用就是让编译器为你自动生成setter与getter方法。

  @synthesize 还有一个作用,可以指定与属性对应的实例变量,例如@synthesize myButton = xxx;那么self.myButton其实是操作的实例变量xxx,而不是_myButton了。


一、传统的get方法和set方法

在正式学习OC的点语法之前,先来看一下传统的get方法和set方法。定义一个Student类,拥有一个成员变量age和对应的get\set方法。

1.Student.h

 1 #import <Foundation/Foundation.h> 
2  
3 @interface Student : NSObject {
4     int age;
5 }
6  
7 - (void)setAge:(int)newAge;
8 - (int)age;
9
10 @end


1> 在第4行定义了一个成员变量age,是@protected权限的,所以外界不能直接访问它

2> 在第7、8行分别声明了age变量的set方法和get方法

 

2.Student.m

 1 #import "Student.h" 
2  
3 @implementation Student
4  
5 - (void)setAge:(int)newAge {
6     age = newAge;
7 }
8  
9 - (int)age {
10     return age;
11 }
12
13 @end


1> 在第5行实现了set方法

2> 在第9行实现了get方法

 

3.main.m

把定义好的Student类放到main函数中使用


 1 #import <Foundation/Foundation.h> 
2 #import "Student.h"
3
 4 int main(int argc, const char * argv[])
 5 {
  6     @autoreleasepool {
  7         Student *stu = [[Student alloc] init];
  8          
  9         // 设置age的值
  10         [stu setAge:10];
  11        
   12         // 取出age的值
   13         int age = [stu age];
   14        
   15         NSLog(@"age is %i", age);
   16        
   17         [stu release];
   18     }
   19     return 0;
   20 }


1> 在2行包含Student的头文件

2> 在第7行创建Student对象,在第17行释放Student对象

3> 在第10行调用set方法设置age的值

4> 在第13行调用get方法获取age的值

5> 在第15行输出age的值,输出结果如下:

2013-04-08 00:26:19.002 点语法[6164:303] age is 10

这就是OC传统的get方法和set方法的简单使用,对初学者来说,这个语法比较奇怪,因为它的方法调用是用方括号[ ]完成的。因此,OC最终引入了点语法。


 二、使用点语法代替传统的get方法和set方法

上面演示了OC传统get\set方法的简单用法,接下来使用点语法来代替。

前面main.m中main函数的代码可以改为:

 1 int main(int argc, const char * argv[]) 
2 {
3     @autoreleasepool {
 4         Student *stu = [[Student alloc] init];
 5          
 6         // 设置age的值
 7         stu.age = 10; // 等价于[stu setAge:10];
 8        
 9         // 取出age的值10         int age = stu.age;
 // 等价于int age = [stu age];
 11        
 12         NSLog(@"age is %i", age);
 13        
  14         [stu release];
  15     }
  16     return 0;
  17 }


1.注意第7行代码,把原来的[stu setAge:10]替换成了stu.age = 10。听清楚了,这两种写法是完全等价的。即这里的stu.age并不是代表直接访问stu对象的成员变量age,而是编译器遇到stu.age = 10的时候会自动将代码展开成[stu setAge:10]

06.点语法_oc点语法

再说,如果是直接访问成员变量的话,OC中应该是这样的语法:stu->age,而不是stu.age。

 

2.注意第10行代码,把原来的int age = [stu age]替换成了int age = stu.age。这两种写法又是完全等价的,stu.age并不是直接访问stu对象的成员变量age,而是编译器遇到int age = stu.age的时候会自动将代码展开成int age = [stu age]

06.点语法_oc点语法_02

 

3.因此,OC中点语法的含义跟Java是完全不一样的,OC点语法的本质是方法调用,不是直接访问成员变量。至于这个点语法代表的是get方法还是set方法,那就取决于你是取值还是设值,取值就是get方法(如第10行代码),设值就是set方法(如第7行代码)。

 

4.如果你想验证点语法是不是方法调用的话,有很多方法。

比如你可以在Student.m的set方法和get方法内部用NSLog加一些打印信息,如果程序运行后有输出打印信息,说明的确是调用了get方法或者set方法


 1 #import "Student.h" 
2  
3 @implementation Student
4  
5 - (void)setAge:(int)newAge {
 6     NSLog(@"调用了setAge方法");
 7     age = newAge;
 8 }
 9
 10 - (int)age {
 11     NSLog(@"调用了age方法");
 12     return age;
 13 }
 14
 15 @end

三、点语法和self的陷阱

1.在Java中,this关键字代表着方法调用者,也就是说,谁调用了这个方法,this就代表谁。所以一般会这样写set方法:

1 public void setAge(int newAge) {
2     this.age = newAge;
3 }

第2行表示将newAge参数的值,赋值给方法调用者的成员变量age

 

2.OC中有个self关键字,作用跟this关键字类似。我这么说完,可能有人就会想这样写OC的set方法了:

1 - (void)setAge:(int)newAge {
2     self.age = newAge;
3 }

第2行中的self代表着当前调用setAge:方法的对象。但是第2行代码是绝对错误的,会造成死循环。因为我在前面已经说过了,OC点语法的本质是方法调用,所以上面的代码相当于:

1 - (void)setAge:(int)newAge {
2     [self setAge:newAge];/error 这里会导致死循环,self会一直调用set方法
3 }

很明显,会造成循环调用setAge:方法,程序就这样崩溃了

 四、一点小建议

如果是第一次接触OC的点语法,你可能会真的 以为stu.age的意思是直接访问stu对象的成员变量age。其实,有一部分原因是因为我这里定义的Student类的成员变量名就叫做age。为了 更好地区分点语法和成员变量访问,一般我们定义的成员变量会以下划线 _ 开头。比如叫做 _age 。

1.Student.h,注意第4行


 1 #import <Foundation/Foundation.h> 
2  
3 @interface Student : NSObject {
4     int _age;
5 }
6
7 - (void)setAge:(int)newAge;
8 - (int)age;
9
10 @end


2.Student.m,注意第6行和第10行


 1 #import "Student.h"
2
3 @implementation Student  
4  
5 - (void)setAge:(int)newAge {
6     _age = newAge;
7 }
8  
9 - (int)age {
10     return _age;
11 }
12
13 @end