关于属性
在C++中,通常需要编写Getter和Setter方法来获取或者是设置实例变量的值。这两种方法需要在程序中显示的完成。这种方式在Objective-C中也是适用的。但是Objective-C提供了一种更为便捷的方式来完成这种功能。它就是属性。和C++中的显示的Getter和Setter方法相比,属性机制使得Getter函数和Setter来的更容易和更简化。
Objectivc-C中的属性是通过关键字@property来声明的。
例如,有类如下:
Student.h文件:
- #import <Foundation/Foundation.h>
- @interface Student : NSObject
- {
- @private
- NSString * name; //学生的姓名
- float math; //数学科目的成绩
- float english; //英语科目的成绩
- }
- -(id)initWithName:(NSString*)aName math:(float)scoreMath english:(float)scoreEnglish;
- -(NSString *)getName;
- -(float)getMath;
- -(float)getEnglish;
- @end
Student.m文件:
- #import "Student.h"
- @implementation Student
- - (id)init
- {
- self = [super init];
- if (self)
- {
- name = nil;
- math = 0;
- english = 0;
- }
- return self;
- }
- -(id)initWithName:(NSString*)aName math:(float)scoreMath english:(float)scoreEnglish
- {
- self = [super init];
- if (self)
- {
- name = aName;
- math = scoreMath;
- english = scoreEnglish;
- }
- return self;
- }
- -(NSString *)getName
- {
- return name;
- }
- -(float)getMath
- {
- return math;
- }
- -(float)getEnglish
- {
- return english;
- }
- - (void)dealloc
- {
- [super dealloc];
- }
- @end
main.m文件如下:
#import <Foundation/Foundation.h>
- #import "Student.h"
- int main (int argc, const char * argv[])
- {
- NSAutoreleasePool * pool = [[NSAutoreleasePool alloc] init];
- Student * p = [[Student alloc] initWithName:@"Mark" math:80.0f english:100.00f];
- NSLog(@"Name:%@",[p getName]);
- NSLog(@"Math:%f",[p getMath]);
- NSLog(@"Math:%f",[p getEnglish]);
- [p release];
- [pool drain];
- return 0;
- }
上面程序的输出结果如下:
Name:Mark
Math:80.000000
Math:100.000000
上面的程序是通过C++中的方式来编写Getter方法来获取私有的实例变量的值。这些个Getter方法实现虽然简单,但是必需有程序员显示书写来完成。应用属性机制后,程序如下:
Student.h文件:
- #import <Foundation/Foundation.h>
- @interface Student : NSObject
- {
- @private
- NSString * name; //学生的姓名
- float math; //数学科目的成绩
- float english; //英语科目的成绩
- }
- @property NSString * name;
- @property float math;
- @property float english;
- -(id)initWithName:(NSString*)aName math:(float)scoreMath english:(float)scoreEnglish;
- //-(NSString *)getName;
- //-(float)getMath;
- //-(float)getEnglish;
- @end
Student.m文件:
- #import "Student.h"
- @implementation Student
- @synthesize name;
- @synthesize math;
- @synthesize english;
- - (id)init
- {
- self = [super init];
- if (self)
- {
- name = nil;
- math = 0;
- english = 0;
- }
- return self;
- }
- -(id)initWithName:(NSString*)aName math:(float)scoreMath english:(float)scoreEnglish
- {
- self = [super init];
- if (self)
- {
- name = aName;
- math = scoreMath;
- english = scoreEnglish;
- }
- return self;
- }
- //-(NSString *)getName
- //{
- // return name;
- //}
- //
- //-(float)getMath
- //{
- // return math;
- //}
- //
- //-(float)getEnglish
- //{
- // return english;
- //}
- //
- //- (void)dealloc
- //{
- // [super dealloc];
- //}
- @end
main.m文件如下:
- #import <Foundation/Foundation.h>
- #import "Student.h"
- int main (int argc, const char * argv[])
- {
- NSAutoreleasePool * pool = [[NSAutoreleasePool alloc] init];
- Student * p = [[Student alloc] initWithName:@"Mark" math:80.0f english:100.00f];
- // NSLog(@"Name:%@",[p getName]);
- // NSLog(@"Math:%f",[p getMath]);
- // NSLog(@"Math:%f",[p getEnglish]);
- NSLog(@"Name:%@",p.name);
- NSLog(@"Math:%f",p.math);
- NSLog(@"Math:%f",p.english);
- [p release];
- [pool drain];
- return 0;
- }
程序的输出如下:
Name:Mark
Math:80.000000
Math:100.000000
可见属性机制使得程序更加简洁明了。
上面程序中引入了新的关键字@synthesize,这个关键字告诉编译器自动为其后面的属性生成Getter()和Setter()方法。需要注意的一点是虽然在描述上适用的是“自动生成Getter()和Setter()方法”,但是实际上我们并看不到生成的对应代码。需要明确的是编译器自动生成的Getter方法:name(),math(),english()以及Sette方法:setName(), setMath(), setEnglish()的调用完全和普通的方法是一样的。例如我们可以修改上面的main()函数如下:
- #import <Foundation/Foundation.h>
- #import "Student.h"
- int main (int argc, const char * argv[])
- {
- NSAutoreleasePool * pool = [[NSAutoreleasePool alloc] init];
- Student * p = [[Student alloc] initWithName:@"Mark" math:80.0f english:100.00f];
- // NSLog(@"Name:%@",[p getName]);
- // NSLog(@"Math:%f",[p getMath]);
- // NSLog(@"Math:%f",[p getEnglish]);
- // NSLog(@"Name:%@",p.name);
- // NSLog(@"Math:%f",p.math);
- // NSLog(@"Math:%f",p.english);
- [p setName:@"Tony"];
- [p setMath:99.0f];
- [p setEnglish:89.98f];
- NSLog(@"Name:%@",[p name]);
- NSLog(@"Math:%f",[p math]);
- NSLog(@"Math:%f",[p english]);
- [p release];
- [pool drain];
- return 0;
- }
程序输出为:
Name:Tony
Math:99.000000
Math:89.980003
上面的程序在Xcode中编译后,会在@property NSString * name;代码的所在行头看到一个黄色的叹号,这表明编译器在该行代码处给出了编译警告。单击该黄色叹号可以看到给出的警告信息:“No 'assign', 'retain', or 'copy' attribute is specified - 'assign' is assumed”和“Default property attribute 'assign' not appropriate for non-gc object”。警告信息的意思是:“没有明确指出应该是assign还是retain或者是copy,却省的是assign”和“缺省得属性设置assign不适合非gc对象 ”,那么这两个警告信息的含义具体是什么呢?assign,retian,copy又分别代表什么含义呢?什么是gc对象呢?什么是非gc对象呢?这些问题见后文描述。