先从传统的方式谈起
- .h中定义类成员变量
- get、set方法
- .m中实现get、set方法
例如,定义一个LFPerson 类,头文件LFPerson.h如下:
1 #import <Foundation/Foundation.h> 2 3 @interface LFPerson : NSObject{ 4 /** 5 * 这边的成员变量都命名 _xxx 6 */ 7 NSString *_userName; 8 int _age; 9 } 10 /** 11 * get方法与变量名相同(去掉_) 12 * 13 * @return 成员变量 14 */ 15 -(NSString *)userName; 16 /** 17 * set 按照java的写法即可 18 * 19 * @param userName 调用set方法时传过来的参数 20 */ 21 -(void)setUserName:(NSString *)userName; 22 23 -(int)age; 24 -(void)setAge:(int)age; 25 26 @end
LFPerson.m文件如下:
1 #import "LFPerson.h" 2 3 @implementation LFPerson 4 5 -(NSString *)userName{ 6 return _userName; 7 } 8 -(void)setUserName:(NSString *)userName{ 9 _userName=userName; 10 } 11 12 13 -(int)age{ 14 if(_age > 0 && _age< 100){ 15 return _age; 16 } 17 return -1; 18 } 19 -(void)setAge:(int)age{ 20 if(age <= 0){ 21 _age = MAXFLOAT; 22 return; 23 } 24 _age=age; 25 } 26 27 @end
mian函数测试代码:
1 #import <Foundation/Foundation.h> 2 #import "LFPerson.h" 3 4 int main(int argc, const char * argv[]) 5 { 6 7 @autoreleasepool { 8 9 LFPerson *person = [[LFPerson alloc]init]; 10 11 [person setUserName:@"afei"]; 12 NSLog(@"%@", [person userName]); 13 14 [person setAge:22]; 15 NSLog(@"%d",[person age]); 16 NSLog(@"%d",person.age);//相当于[person age],即调用get方法
17 18 } 19 return 0; 20 }
测试结果如下:
每次要为一个属性写上getter和setter,其实是十分麻烦的,所以苹果为OC引入了@property,用来改进setter和getter
利用@property特性,改进后的LFPerson.h
1 #import <Foundation/Foundation.h> 2 3 @interface LFPerson : NSObject 4 5 @property(nonatomic,copy,getter = getUserName) NSString *name; 6 @property(nonatomic,assign) int age; 7 @property(nonatomic,assign) int height; 8 9 @end
改进后的LFPerson.m
1 #import "LFPerson.h" 2 3 @implementation LFPerson 4 5 @end
可以看到,LFPerson.m已经很干净清爽了!这正是@property自动生成get、set带来的方便之处。
mian函数:
1 #import <Foundation/Foundation.h> 2 #import "LFPerson.h" 3 4 int main(int argc, const char * argv[]) 5 { 6 7 @autoreleasepool { 8 9 LFPerson *person = [[LFPerson alloc]init]; 10 11 [person setName:@"afei"];//调用set方法,编译器自动生成 12 NSLog(@"%@", [person getUserName]);//调用get方法,@property中指定为getter为getUseNname 13 14 person.age = 22;//.语法调用set方法 15 NSLog(@"%d",[person age]);//调用get方法,编译器自动生成,方法名与属性名相同,注意与调用setName的不同,这是apple的命名规则 16 17 person.height = 170; 18 NSLog(@"height:%d",person.height); 19 20 } 21 return 0; 22 }
main函数测试结果:
重写@property中自动生成的set、get方法
LFPerson.h
1 #import <Foundation/Foundation.h> 2 3 @interface LFPerson : NSObject 4 5 @property(nonatomic,copy,getter = getUserName) NSString *name; 6 @property(nonatomic,assign) int age; 7 @property(nonatomic,assign) int height; 8 9 @end
LFPerson.m中,需要重写set、get方法
1 #import "LFPerson.h" 2 3 @interface LFPerson () 4 5 @end 6 7 @implementation LFPerson 8 9 @synthesize age = _age;//同时重写set、get方法就需要写@synthesize xxx = _xxx 10 //@synthesize name = _name; 11 @synthesize height = HH; 12 13 /** 14 * 重写getter方法,并且getter方法名字是在@property中指定好的,这里只重写get方法,所以可以不用指定@synthesize 15 * 16 * @return 返回字段 17 */ 18 -(NSString *)getUserName{ 19 NSString *tmp = [[NSString alloc]initWithFormat:@"the "]; 20 return [tmp stringByAppendingString:_name]; 21 } 22 23 24 /** 25 * 重写get方法,默认的get方法与变量名相同 26 * 27 * @return 实际age+10 28 */ 29 30 -(int) age{ 31 return _age+10; 32 } 33 34 -(void)setAge:(int)age{ 35 _age = age+80; 36 } 37 38 -(void)setHeight:(int) height{ 39 HH = height+10;//因为写了 @synthesize height = HH; 所以成员变量名就是HH了,不写的话,成员变量默认就是 _height了 40 } 41 -(int)height{ 42 return HH+1; 43 } 44 45 @end
mian函数
1 #import <Foundation/Foundation.h> 2 #import "LFPerson.h" 3 4 int main(int argc, const char * argv[]) 5 { 6 7 @autoreleasepool { 8 9 LFPerson *person = [[LFPerson alloc]init]; 10 11 [person setName:@"afei"]; 12 NSLog(@"%@", person.name); 13 14 [person setAge:22]; 15 NSLog(@"%d",[person age]); 16 17 person.height = 170; 18 NSLog(@"height:%d",person.height); 19 20 } 21 return 0; 22 }
main函数测试结果如下:
在这里我说明一下@synthesize的作用:
1、一个作用就是让编译器为你自动生成setter与getter方法
2、可以指定与属性对应的实例变量,如@synthesize height = HH(如果.m文件中写了@synthesize str = xxx;那么生成的实例变量就是xxx;如果没写@synthesize str;那么生成的实例变量就是_str)
3、从xcode 4.5及以后的版本中,@property独揽了@property和@synthesize的功能。
@property (nonatomic, copy) NSString *str;这句话完成了3个功能:
1) 生成_str成员变量的get和set方法的声明
2) 生成_str成员变量set和get方法的实现
3) 生成一个_str的成员变量。(注意:这种方式生成的成员变量是private的)
总结:属性重写setter和getter方法
使用属性@property能够帮我们省去了很多繁杂的工作,但有的时候我们在使用属性的时候还是需要去重写一下其setter和getter方法,这个时候我们应该怎么做呢?
- 如果只重写setter和getter其中之一
可以直接重写
- 如果同时重写setter和getter
需要加上@synthesize propertyName = _propertyName;不然系统会不认_str。因为如果你同时重写了getter和setter方法,系统就不会帮你自动生成这个_str变量,所以当然报错说不认识这个变量。所以得手动指定成员变量,然后再同时重写了getter和setter方法。