编程笔记(Objective-c:属性的实现)

转载请标明出处:blog.csdn.net/zhangxingping
前面的示例程序中已经看到了使用@synthesize关键字来告诉编译器自动生成属性的getter和setter方法。也就是说如果我们没有显示地在@implementation代码块中实现属性的getter和setter方法,编译器会自动根据property的attributes来生成相应的getter和setter。其实我们在使用@synthesize指令的时候还可以为属性指定特定的实例变量。此时,对属性的操作相当于是对该实例变量的操作。通用形式如下:

@synthesize 属性名称 = 实例变量名称;

例如,之前的程序可以修改为:

Student.h:

  1. #import<Foundation/Foundation.h>
  2. @interfaceStudent:NSObject
  3. {
  4. @public//将下面的三个实例变量修改为是公有的,以便输出其值,和属性的值进行对比
  5. NSString*name;//学生的姓名
  6. <prename="code"class="cpp">
float math; //数学科目的成绩 float english; //英语科目的成绩 }//@property (retain) NSString * name;@property (retain) NSString * fullName;@property float math;@property float english; -(id)initWithName:(NSString*)aName math:(float)scoreMath english:(float)scoreEnglish;@end
 

Student.m:

  1. #import"Student.h"
  2. @implementationStudent
  3. //@synthesizename;
  4. //为fullName属性指定实例变量为name,以后对fullName的操作相当于是对name的操作
  5. @synthesizefullName=name;
  6. @synthesizemath;
  7. @synthesizeenglish;
  8. -(id)init
  9. {
  10. self=[superinit];
  11. if(self)
  12. {
  13. name=nil;
  14. math=0;
  15. english=0;
  16. }
  17. returnself;
  18. }
  19. -(id)initWithName:(NSString*)aNamemath:(float)scoreMathenglish:(float)scoreEnglish
  20. {
  21. self=[superinit];
  22. if(self)
  23. {
  24. name=aName;
  25. math=scoreMath;
  26. english=scoreEnglish;
  27. }
  28. returnself;
  29. }
  30. -(void)dealloc
  31. {
  32. [superdealloc];
  33. }
  34. @end

main.m:

  1. #import<Foundation/Foundation.h>
  2. #import"Student.h"
  3. intmain(intargc,constchar*argv[])
  4. {
  5. NSAutoreleasePool*pool=[[NSAutoreleasePoolalloc]init];
  6. Student*p=[[Studentalloc]initWithName:@"Mark"math:80.0fenglish:100.00f];
  7. NSLog(@"Name:%@",[pfullName]);//输出属性的值
  8. NSLog(@"Name:%@",p->name);//输出实例变量的值
  9. NSLog(@"Math:%f",[pmath]);
  10. NSLog(@"English:%f",[penglish]);
  11. //[psetName:@"Tony"];
  12. [psetFullName:@"Tony"];//设置属性的值
  13. [psetMath:99.0f];
  14. [psetEnglish:89.98f];
  15. NSLog(@"Name:%@",[pfullName]);//输出属性的值
  16. NSLog(@"Name:%@",p->name);//输出实例变量的值
  17. NSLog(@"Math:%f",[pmath]);
  18. NSLog(@"English:%f",[penglish]);
  19. [prelease];
  20. [pooldrain];
  21. return0;
  22. }


上面程序的输出如下:

Name:Mark

Name:Mark

Math:80.000000

English:100.000000

Name:Tony

Name:Tony

Math:99.000000

English:89.980003

可见这种为属性指定实例变量的方法使得对属性的操作变成了对实例变量的操作。那么在之前的程序中,我们并没有为属性指定实例变量,此时对属性的操作也是相当于对实例变量的操作嘛?如果是,那是对那些实例变量的操作呢?我们来看看下面程序的运行结果:

Student.h文件:

  1. #import<Foundation/Foundation.h>
  2. @interfaceStudent:NSObject
  3. {
  4. @public
  5. NSString*name;//学生的姓名
  6. floatmath;//数学科目的成绩
  7. floatenglish;//英语科目的成绩
  8. }
  9. //下面三个属性的类型,名称和类的三个实例变量的类型,名称完全相同
  10. @property(retain)NSString*name;
  11. @propertyfloatmath;
  12. @propertyfloatenglish;
  13. -(id)initWithName:(NSString*)aNamemath:(float)scoreMathenglish:(float)scoreEnglish;
  14. @end
Student.m文件:

  1. #import"Student.h"
  2. @implementationStudent
  3. //synthesize指令并没有为这三个属性指定实例变量
  4. @synthesizename;
  5. @synthesizemath;
  6. @synthesizeenglish;
  7. -(id)init
  8. {
  9. self=[superinit];
  10. if(self)
  11. {
  12. name=nil;
  13. math=0;
  14. english=0;
  15. }
  16. returnself;
  17. }
  18. -(id)initWithName:(NSString*)aNamemath:(float)scoreMathenglish:(float)scoreEnglish
  19. {
  20. self=[superinit];
  21. if(self)
  22. {
  23. name=aName;
  24. math=scoreMath;
  25. english=scoreEnglish;
  26. }
  27. returnself;
  28. }
  29. -(void)dealloc
  30. {
  31. [namerelease];
  32. [superdealloc];
  33. }
  34. @end
main.m文件:

  1. #import<Foundation/Foundation.h>
  2. #import"Student.h"
  3. intmain(intargc,constchar*argv[])
  4. {
  5. NSAutoreleasePool*pool=[[NSAutoreleasePoolalloc]init];
  6. Student*p=[[Studentalloc]initWithName:@"Mark"math:80.0fenglish:100.00f];
  7. NSLog(@"Name:%@",[pname]);
  8. NSLog(@"Name:%@",p->name);
  9. NSLog(@"Math:%f",[pmath]);
  10. NSLog(@"Math:%f",p->math);
  11. NSLog(@"English:%f",[penglish]);
  12. NSLog(@"English:%f",p->english);
  13. [psetName:@"Tony"];
  14. [psetMath:99.0f];
  15. [psetEnglish:89.98f];
  16. NSLog(@"Name:%@",[pname]);
  17. NSLog(@"Name:%@",p->name);
  18. NSLog(@"Math:%f",[pmath]);
  19. NSLog(@"Math:%f",p->math);
  20. NSLog(@"English:%f",[penglish]);
  21. NSLog(@"English:%f",p->english);
  22. [prelease];
  23. [pooldrain];
  24. return0;
  25. }

上面程序的输出为:

Name:Mark

Name:Mark

Math:80.000000

Math:80.000000

English:100.000000

English:100.000000

Name:Tony

Name:Tony

Math:99.000000

Math:99.000000

English:89.980003

English:89.980003

可见在使用@synthesize指令的时候,如果没有为属性指定实例变量,并且属性的类型和名称与实例变量的类型和名称相同的情况下,会自动为该属性指定了同名的实例变量。那如果没有为属性指定实例变量,且类中没有与该属性类型和名称都相同的实例变量,会出现什么样的情况了?例如,将上述程序中对name属性的声明,实现以及调用都修改为Name,完整程序如下:

Student.h文件

  1. #import<Foundation/Foundation.h>
  2. @interfaceStudent:NSObject
  3. {
  4. @public
  5. NSString*name;//学生的姓名
  6. floatmath;//数学科目的成绩
  7. floatenglish;//英语科目的成绩
  8. }
  9. @property(retain)NSString*Name;//此处Name首字母为大写,以便和类的实例变量name进行区分
  10. @propertyfloatmath;
  11. @propertyfloatenglish;
  12. -(id)initWithName:(NSString*)aNamemath:(float)scoreMathenglish:(float)scoreEnglish;
  13. @end

Student.m文件:

  1. #import"Student.h"
  2. @implementationStudent
  3. @synthesizeName;//此处Name首字母为大写,以便和类的实例变量name进行区分
  4. @synthesizemath;
  5. @synthesizeenglish;
  6. -(id)init
  7. {
  8. self=[superinit];
  9. if(self)
  10. {
  11. name=nil;
  12. math=0;
  13. english=0;
  14. }
  15. returnself;
  16. }
  17. -(id)initWithName:(NSString*)aNamemath:(float)scoreMathenglish:(float)scoreEnglish
  18. {
  19. self=[superinit];
  20. if(self)
  21. {
  22. name=aName;
  23. math=scoreMath;
  24. english=scoreEnglish;
  25. }
  26. returnself;
  27. }
  28. -(void)dealloc
  29. {
  30. [Namerelease];
  31. [superdealloc];
  32. }
  33. @end

main.m文件:

  1. #import<Foundation/Foundation.h>
  2. #import"Student.h"
  3. intmain(intargc,constchar*argv[])
  4. {
  5. NSAutoreleasePool*pool=[[NSAutoreleasePoolalloc]init];
  6. Student*p=[[Studentalloc]initWithName:@"Mark"math:80.0fenglish:100.00f];
  7. NSLog(@"Name:%@",[pName]);
  8. NSLog(@"Name:%@",p->name);
  9. NSLog(@"Math:%f",[pmath]);
  10. NSLog(@"Math:%f",p->math);
  11. NSLog(@"English:%f",[penglish]);
  12. NSLog(@"English:%f",p->english);
  13. [psetName:@"Tony"];
  14. [psetMath:99.0f];
  15. [psetEnglish:89.98f];
  16. NSLog(@"Name:%@",[pName]);
  17. NSLog(@"Name:%@",p->name);
  18. NSLog(@"Math:%f",[pmath]);
  19. NSLog(@"Math:%f",p->math);
  20. NSLog(@"English:%f",[penglish]);
  21. NSLog(@"English:%f",p->english);
  22. [prelease];
  23. [pooldrain];
  24. return0;
  25. }

上面程序的输出如下:

Name:(null)

Name:Mark

Math:80.000000

Math:80.000000

English:100.000000

English:100.000000

Name:Tony

Name:Mark

Math:99.000000

Math:99.000000

English:89.980003

English:89.980003

从输出结果可以看出显然属性Name和实例变量name不是同一个对象。注意,上面的代码在objectivc-c2.0 以前的版本上可能会报告错误。这是因为之前的版本中要求属性必须指定对应的实例变量。如果不显示指定对应的实例变量,则会以类中同名的实例变量对应,如果没有同名的实例变量,编译就会报告错误。在0bjective-2.0版本中取消了这个限制,因此上面的程序是可以编译通过并且运行的。只是在没有显示指定属性对应的实例变量的时候,也没有同名实例变量的时候,属性单独存在不和任何的实例变量对应。因此上面程序输出结果中的Name:一项,属性和实例变量的值是不一样的。

除了@synthesize指令外,还有一个用于实现属性的指令:@dynamic。这个指令告诉编译器我们会显示地实现该属性的getter和setter方法,或者是该属性的getter和setter方式是通过别的方式来完成的,比如动态加载代码以及动态方法解析等方式。如果实现属性时使用的是@dynamic指令,却没有通过上述的方式来实现该属性的getter和setter方法,编译是不会报告错误的,但程序会在运行的时候出错。例如下面的程序:

Student.h:

  1. #import<Foundation/Foundation.h>
  2. @interfaceStudent:NSObject
  3. {
  4. @public
  5. NSString*name;//学生的姓名
  6. floatmath;//数学科目的成绩
  7. floatenglish;//英语科目的成绩
  8. }
  9. @property(retain)NSString*fullName;
  10. @propertyfloatmath;
  11. @propertyfloatenglish;
  12. -(id)initWithName:(NSString*)aNamemath:(float)scoreMathenglish:(float)scoreEnglish;
  13. @end

Student.m

  1. #import"Student.h"
  2. @implementationStudent
  3. @dynamicfullName;
  4. @synthesizemath;
  5. @synthesizeenglish;
  6. -(id)init
  7. {
  8. self=[superinit];
  9. if(self)
  10. {
  11. name=nil;
  12. math=0;
  13. english=0;
  14. }
  15. returnself;
  16. }
  17. -(id)initWithName:(NSString*)aNamemath:(float)scoreMathenglish:(float)scoreEnglish
  18. {
  19. self=[superinit];
  20. if(self)
  21. {
  22. name=aName;
  23. math=scoreMath;
  24. english=scoreEnglish;
  25. }
  26. returnself;
  27. }
  28. -(void)dealloc
  29. {
  30. //[namerelease];
  31. [superdealloc];
  32. }
  33. //-(NSString*)fullName
  34. //{
  35. //returnname;
  36. //}
  37. //
  38. //
  39. //-(void)setFullName:(NSString*)aName
  40. //{
  41. //[aNameretain];
  42. //[namerelease];
  43. //name=aName;
  44. //}
  45. @end

main.m:

  1. #import<Foundation/Foundation.h>
  2. #import"Student.h"
  3. intmain(intargc,constchar*argv[])
  4. {
  5. NSAutoreleasePool*pool=[[NSAutoreleasePoolalloc]init];
  6. Student*p=[[Studentalloc]initWithName:@"Mark"math:80.0fenglish:100.00f];
  7. //程序运行时,会在该行处报告异常:unrecognizedselectorsenttoinstance0Xxxxxx
  8. NSLog(@"Name:%@",[pfullName]);
  9. NSLog(@"Name:%@",p->name);
  10. NSLog(@"Math:%f",[pmath]);
  11. NSLog(@"Math:%f",p->math);
  12. NSLog(@"English:%f",[penglish]);
  13. NSLog(@"English:%f",p->english);
  14. [psetFullName:@"Tony"];
  15. [psetMath:99.0f];
  16. [psetEnglish:89.98f];
  17. NSLog(@"Name:%@",[pfullName]);
  18. NSLog(@"Name:%@",p->name);
  19. NSLog(@"Math:%f",[pmath]);
  20. NSLog(@"Math:%f",p->math);
  21. NSLog(@"English:%f",[penglish]);
  22. NSLog(@"English:%f",p->english);
  23. [prelease];
  24. [pooldrain];
  25. return0;
  26. }

可见在使用@dynamic指令后,由于没有实现fullName的getter方法而导致程序异常。将Student.m中的getter和setter方法的注释//去掉,并将dealloc方法中的注释也去掉,再次编译运行程序结果如下:

Name:Mark

Name:Mark

Math:80.000000

Math:80.000000

English:100.000000

English:100.000000

Name:Tony

Name:Tony

Math:99.000000

Math:99.000000

English:89.980003

English:89.980003

你可能感兴趣的:(Objective-C)