您的位置:首页 > 运维架构

OC 中"烦人"的小特性之getter和setter以及property编译指令

2015-09-29 17:34 274 查看
记得以前学C/C++/java时也接触过类似于类的实现问题. 只有在Java的类实现时,有一个不成文的小标准,就是需要为类中的成员变量实现一个getter和setter方法.

当时觉得就是给成员变量赋值和取值的时候更方便,更有独立性,逼格更高点,呵呵~ 所以在学习OC时也没有特别的在意,就是一目十行的瞟了一眼,以为就是那点事.

但是到了后的学习发现,貌似跟想想中的有点出入.当然了,关于IOS的学习书籍中,国内的书都是不负责的,好点的前面部分会给你讲一些基础的OC.

然后上来就给你展示一堆的控件,让你满足感瞬间爆棚.但是对于基础的语言特性几乎不讲,当你自己学代码的时候,会一头雾水.

好了说重点,上菜先.

@interface Person : NSObject{
int _age;

}

-(void) setAge: (int) age;

-(int) age;

@end
@implementation Person

-(void) setAge: (int) age{
_age = age;
}

-(int) age{

return _age;
}

@end


int main(int argc, const char * argv[]) {
@autoreleasepool {
Person * perabc = [[Person alloc] init];

perabc.age = 100;

NSLog(@"age = %d", perabc.age);

}
return 0;
}

在Java中给成员变量配setter和getter方法时只需要结果实现就行了 ,过程什么的不重要,但是在OC中这是绝对不行的.
有一些"烦人"的特性:



setter方法:

-(void) setAge: (int) age;

getter方法:

-(int) age;

修改任何一点都将导致编译不通过.

========================

补充一下, 当我们在使用"."  点语法的时候, 实际上就是在调用相应的getter 和setter方法, 当给成员赋值的时候 当然调用的就是setter 方法, 需要取值的时候当然就是getter方法

至于编译器是怎么判断的,这我们就不去深究了, 记得以前在一本C语言的书上说是什么左值 什么的,估计就是那个...

=========================
@interface Person : NSObject{
int _age;

}

定义的类中, 成员变量名 "_age"的下划线并非是必须的,这儿可以是任意命名.只要符合命名规则就ok.
在实现的setter和getter方法中也是一样的.
=============================

property编译指令

当我们的类中成员变量 很多时候,再加上 OC中的特性,在不使用"->" 语法的时候,就必须实现很多个getter和setter方法

为了简化操作,我们通过编译指令,@property 

在高版本的XCODE 中对该指令进行了 加强.较早的版本中

@property是实现getter和setter方法的定义

@synthesize是实现getter和setter方法的具体实现

较高版本中我们只需要一个@property就可以完成定义与实现



上面提到了,在使用property时候会生成一个私有的成员变量,该变量的名字是成员变量的名字前加下划线, "_成员名".

@interface Person : NSObject{
@public int ages;

}

@property (nonatomic, assign) int age;

@end

这个类中,本身的成员变量名字为ages, 我们又定义了一个 @property (nonatomic, assign) int age;  也就是又定义了一个age变量
其实一般不这样写,这是为了说明,此时 ages和age是并存的,而且还有一个property生成的 "_age"变量,只不过该变量只是在该指令所完成的setter和getter方法的内部使用

当我们重写getter和setter方法时就需要使用到,看代码

@implementation Person

-(void) setAge: (int) age{
_age = age + 10;
}

@end


但是此处又会出现一个问题, 我们上面提到了,OC 中setter和getter方法的规则,   那么此处我们应该用setAge 还是setAges呢???  
这两种方法语法上都没问题, 我们在写了 "_age =  age  +  10;" 这条语句,  然后在main函数中 调用setter方法

  Person * perabc = [[Person alloc] init];

perabc.age = 100;

NSLog(@"%d", perabc.age);


此时输出是110
然后我们修改代码

@implementation Person

-(void) setAges: (int) age{
_age = age + 100; //需要手动完成getter方法以及 修改perabc.age = 100; 为 perabc.ages = 100;
}

@end

我们现在使用setAges这个名字, 此时又会输出什么呢???
此时输出的是200

好了, 这怎么解释呢...

当我们使用setAge 的时候, 是重写了由@property所生成的setter方法

当我们使用setAges的时候, 我们是给类中的 @public int ages; 的成员变量实现setter方法

那么这一切就解释通了,也再一次强调了,我们上面提到的一系列OC中关于setter和getter方法..也就是名字的重要性.

==============================

刚才我们还提到过 "  其实一般不这样写,这是为了说明,此时 ages和age是并存的,而且还有一个property生成的 "_age"变量  "

那么通过 上面的 110 和 200 的输出结果是否也 说明了这个问题.他们确实是并存的,  只不过由于我们在代码中使用了 点语法,  而点语法的作用就是去调用setter 和getter方法

相当于进行了一次透明的封装,以及调用.我们没怎么感受到而已. 我们只需要在输出语句中不使用点语法就可以验证

在这条语句下再加一条 不适用点语法的语句
NSLog(@"%d", perabc.age); //使用setAge方法
NSLog(@"%d", perabc->ages); //使用setAge方法

此时输出是110  和  0
 因为类中定义的ages没有被赋值,只是进行了简单的初始化所以是0, 也就验证了并存性.

我还试着访问property 生成的私有_age变量, 但是无法实现,只能在重写的setter方法中使用. 

在实际应用中,往往一个成员一条property语句就行了 , 然后根据需要重写相应的sette和getter方法即可

@interface Person : NSObject

@property (nonatomic, assign) int age;

@end

==============================

先写的到这,以后遇到问题再补充..
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签:  oc getter setter pro