【转】Objective-C学习笔记七:类的定义一
2013-03-10 17:37 maying_07 阅读(156) 评论(0) 编辑 收藏 举报原文地址:http://sarin.iteye.com/blog/1761576
我们还是结合之前分数的示例来说明,只是更为详尽。使用XCode创建新的项目Fraction,然后创建Fraction类,此时XCode为我们生成两个文件:Fraction.h和Fraction.m。我们在Fraction.h这个头文件中定义分数类Fraction,在Fraction.m中编写分数类的实现代码,在main.m中编写测试程序。那么在XCode中我们得到如下的项目结构:
来看下头文件中的类定义:
1 // 2 // Fraction.h 3 // Fraction 4 // 5 // Created by Nan Lei on 13-1-1. 6 // Copyright (c) 2013年 Nan Lei. All rights reserved. 7 // 8 9 #import <Foundation/Foundation.h> 10 11 @interface Fraction : NSObject 12 13 -(void) print; 14 -(void) setNumerator: (int) n; 15 -(void) setDenominator: (int) d; 16 -(int) numerator; 17 -(int) denominator; 18 -(double) convertToNum; 19 20 @end
这里的头文件也可以叫做接口文件,它会告知编译器Fraction类的特征,就是包含六个实例方法(用"-"定义的方法)。Fraction类的实现会编写在Fraction.m文件中,代码如下:
1 // 2 // Fraction.m 3 // Fraction 4 // 5 // Created by Nan Lei on 13-1-1. 6 // Copyright (c) 2013年 Nan Lei. All rights reserved. 7 // 8 9 #import "Fraction.h" 10 11 @implementation Fraction 12 { 13 int numerator; 14 int denominator; 15 } 16 17 -(void) print 18 { 19 NSLog(@"%i/%i",numerator,denominator); 20 } 21 22 -(void) setNumerator:(int)n 23 { 24 numerator=n; 25 } 26 27 -(void) setDenominator:(int)d 28 { 29 denominator=d; 30 } 31 32 -(int) numerator 33 { 34 return numerator; 35 } 36 37 -(int) denominator 38 { 39 return denominator; 40 } 41 42 -(double) convertToNum 43 { 44 if(denominator!=0){ 45 return (double)numerator/denominator; 46 }else{ 47 return NAN; 48 } 49 } 50 51 @end
这和我们之前示例中的是一样的,这里注意一点import语句,我们使用双引号("")来导入头文件,而不是尖括号(<>),原因是Fraction.h是我们自定义的头文件,而不是系统提供的。这样编译器就知道该从什么地方来找到指定的头文件,当然,如果有必要,可以使用更为详细的路径(当我们在不同包下定义了相同的类名的类时)来查找不同位置。
最后来看main.m文件,这是我们之前没有做的一个文件,此时我们拆分main函数到main.m文件中,代码如下:
1 // 2 // main.m 3 // Fraction 4 // 5 // Created by Nan Lei on 13-1-1. 6 // Copyright (c) 2013年 Nan Lei. All rights reserved. 7 // 8 9 #import "Fraction.h" 10 11 int main(int argc, const char * argv[]) 12 { 13 @autoreleasepool { 14 Fraction *fractionA = [Fraction new]; 15 Fraction *fractionB = [Fraction new]; 16 17 [fractionA setNumerator:1]; 18 [fractionA setDenominator:3]; 19 20 NSLog(@"The value of fractionA is %g",[fractionA convertToNum]); 21 22 NSLog(@"fractionB is %i / %i",fractionB.numerator,fractionB.denominator); 23 NSLog(@"The value of fractionB is %g",[fractionB convertToNum]); 24 } 25 return 0; 26 }
要注意这里的import语句,我们仍然引入的是头文件,而不是实现文件。也就是我们只需获取类定义部分的信息就可以了,系统处理时会为我们寻找实现的方法。
这样的代码结构对于之前看到的简单示例来说就复杂多了,这是我们扩大程序规模的必经之路,也更为实用。
我们在上述代码中的Fraction实现文件中编写了两个属性numerator和denominator,并且提供了设置值和取值的方法(类似Java的getter和setter方法),其实更好的写法是在接口文件中使用@property指令来定义属性,还可以省略掉设置值和取值的方法(系统会自动为我们实现),那么Fraction.h的代码修改如下:
1 #import <Foundation/Foundation.h> 2 3 4 @interface Fraction : NSObject 5 6 @property int numerator,denominator; 7 8 -(void) print; 9 -(double) convertToNum; 10 11 @end
这样一来,代码就简单很多,那么在实现文件Fraction.m中使用@synthesize指令即可完成对属性numerator和denominator的设置值和取值操作:
1 #import "Fraction.h" 2 3 @implementation Fraction 4 5 @synthesize numerator,denominator; 6 7 -(void) print 8 { 9 NSLog(@"%i/%i",numerator,denominator); 10 } 11 12 -(double) convertToNum 13 { 14 if(denominator!=0){ 15 return (double)numerator/denominator; 16 }else{ 17 return NAN; 18 } 19 } 20 21 @end
在XCode中运行代码,我们就得到如下的结果:
说明我们的代码是正确的。
我们使用了@property指令,就不用在实现部分定义相应的实例变量,使用@synthesize指令就会告诉编译器为我们生成设置值和取值的方法。方法命名规范是设置值方法setX(x是我们的变量名),注意大小写(和Java Bean的访问器方法类似),取值方法名就是变量名x。当然我们也可以使用点运算符来访问属性,比如我们代码中的写法。同时使用点运算符来为属性赋值也是可以的,只是在代码中没有体现出来。
比如instance.property=value等价于[instance setProperty: value],比如instance.property等价于[instance property]的写法。
之前的代码中我们的方法参数都为一个,下面来看看带有多个参数的方法该如何定义和使用。我们继续来改写分数类Fraction,提供一个可以同时设置分子和分母的方法,很容易想到如下语句[fractionA setNumerator:1 setDenominator:3],这是我们很容易想到的方式,但是该方式不具备一个易于理解的方法名,其实我们可以这样来定义这个方法:
1 -(void) setTo: (int) n over: (int) d;
下面修改头文件的定义,代码如下:
1 #import <Foundation/Foundation.h> 2 3 @interface Fraction : NSObject 4 5 @property int numerator,denominator; 6 7 -(void) print; 8 -(double) convertToNum; 9 -(void) setTo:(int) n over: (int) d; 10 11 @end
这里我们加入了这个方法的定义,那么实现该方法,代码如下:
1 #import "Fraction.h" 2 3 @implementation Fraction 4 5 @synthesize numerator,denominator; 6 7 -(void) print 8 { 9 NSLog(@"%i/%i",numerator,denominator); 10 } 11 12 -(double) convertToNum 13 { 14 if(denominator!=0){ 15 return (double)numerator/denominator; 16 }else{ 17 return NAN; 18 } 19 } 20 21 -(void) setTo:(int)n over:(int)d 22 { 23 numerator=n; 24 denominator=d; 25 } 26 27 @end
最后修改主函数来进行测试:
1 #import "Fraction.h" 2 3 int main(int argc, const char * argv[]) 4 { 5 @autoreleasepool { 6 Fraction *fractionA = [Fraction new]; 7 Fraction *fractionB = [Fraction new]; 8 9 [fractionA setTo:10 over:406]; 10 [fractionB setTo:23 over:901]; 11 12 [fractionA print]; 13 [fractionB print]; 14 } 15 return 0; 16 }
编译运行,我们得到如下的结果:
带有多个参数的方法在定义时,参数名称是可选的,比如上面的方法我们还可以定义为如下形式:-(int) set: (int) n: (int) d;显然这里没有对第二个参数命名,那么调用该方法时,我们可以这样做[fractionA set: 10: 406],虽然可以这么做,但是省略参数名的做法是不推荐的,因为可能会引起语义不清等问题。如果参数很多或者参数很重要,可能就会引起大问题。