通常,类的声明(@interface部分)要放在它自己的名字为class.h的文件中
类的定义(@implementation部分包含的代码)通常放在相同名称的文件中,但扩展名要使用 .m
所以,对与一个Fraction 类,类的声明放到Fraction.h文件中,类的定义放到Fraction.m 文件中
在Xcode中如何创建:
File -> New File ->左侧窗口选择Cocoa Touch ->右上格中选Objective_C class -> Next选择 Subclass of NSObjects -> Next -> 在Save As 框中输入Fraction.m (Fraction为新创建的类名) 其他保持默认 ->Save这样便创建以类名为命名的 .h 和 .m 文件, 还要创建一个 .m 文件,里面写main 程序注意:要使用以下语句将接口文件导入实现文件中:#import "Fraction.h" // Fraction 是一个类名
合并存取方法
合并存储就是可以自动生成设置方法和取值方法第一步: 在接口部分(.h文件)使用@property 指令标示属性。
@interface Fraction : NSObject@ property int numerator, denominator;-(void) print;-(double) convertToNum;@end
第二步: 在实现部分使用 @synthesize 指令
测试:#import "Fraction.h"@implementation Fraction@ synthesize numerator, denominator;-(void) print{}-(double) convertToNum{}
@autoreleasepool {
Fraction *myFraction = [[Fraction alloc] int];[myFraction setNumerator: 1];
}
如果使用了@property命令,就不需要在实现部分声明相应的实例变量,当然也可以再声明相应的实例变量,但是那不是必须要做的,编译去会有些提示。@synthesize命令是为两个属性生成以对设值方法和取值方法。使用合成的存储方法,属性名称前不要以new,alloc,copy,init开头
@property 的参数@property (copy, nonatomic) NSString *name, email;属性 copy 和 nonatomic 特性,copy特性会在setter方法内生成实例变量的副本,默认的方法不会生成副本,仅仅进行赋值。比如 就等同于没有copy 特性时:-(void) setName: (NSString *) theName{name = theName;}有了copy 特性:-(void) setName: (NSString *) theName{
if (name != theName)
name = [NSString stringWithString: theName];
}
nonatomic 特性表明不必担心在竞争条件下多个线程试图同时获取实例变量的情形。
使用点运算符访问属性
在OC中可以使用 "[myFraction numerator]; " 来向myFraction 对象发送 numerator 消息,从而返回所需的值。同时也可以使用点运算符 : myFraction.numerator
之前对方法传参时,如下:[myFraction setNumerator: 1];[myFraction setDenominator: 3];等价于:myFraction.numerator = 1;myFraction.denominator = 3;
点运算符通常用在属性上,用于设置或获取实例变量的值。而其他方法通常使用传统的方括号形式的消息表达式做为首选语法
具有多个参数的方法
在设置numerator 和 denominator 时我们需要分别设置,现在可以定义一个方法能直接设置两个参数就好了。定义一个方法 setTo:over:
首先在接口文件中添加 setTo:over: 声明:@interface Fraction : NSObject@ property int numerator, denominator;-(void) print;-(double) convertToNum;-(void) setTo: (int) n over: (int) d;然后在实现文件中添加新方法的定义:@end
#import "Fraction.h"@implementation Fraction@ synthesize numerator, denominator;-(void) print{}-(double) convertToNum{}-(void) setTo: (int) n over: (int) d{
numerator = n;denominator = d;
}@end
测试:@autoreleasepool {Fraction *myFraction = [[Fraction alloc] int];
[myFraction setTo:1 over:3];}注意: 参数可以没有命名,如下:-(int) set: (int) n: (int) d;和刚刚的例子相比,没有参数名。 但是调用该方法时可以使用冒号做分隔符。[myFraction set:1 :3];但是最好不要省略参数名。这不是个好习惯
方法的参数
方法的参数是局部变量,而且,通过方法传递过来的任何参数都被复制到局部变量中,所以说,方法不会改变参数的原值,但是如果参数是一个对象的话是可以改变对象的实例变量值的。因为对象其实是一个数据存储位置的引用
比如想实现两个分数相加可以定义一个方法:add: (Fraction *)f因为该方法的参数是一个对象。所以我们通过对象可以直接指定这个对象的实例变量并直接通过名字发送消息,获取实例变量的值,从而完成分数相加-(void)add: (Fraction *) f{
// a/b + c/d = (a*d + b*c)/(b*d)
numerator = numerator * f.denominator + denominator * f.numerator;denominator = denominator * f.denominator;
}
self 关键字
我们知道如何通过名称指明方法内部的实例变量(eg: [myFraction denominator]; ),但是不知道如何直接指明消息的接收者。self关键字可以用来指明消息的对象是当前方法的接收者。比如:使用刚刚的方法 add: (Fraction *)f 虽然能计算出分子分母,但是会出现 6/8 这种为约分的情况。我们可以定义一个方法:reduce 对分子分母进行约分。-(void) reduce //求最大公约数{
int u = numerator;int v = denominator;int temp;
while (v != 0) {
}temp = u%v;u = v; v = temp;
numerator /= u;denominator /= u;
}
}
我们可以在 add 方法的最后添加下一行代码调用 reduce 方法[self reduce];reduce 消息取得了发送给add:消息的接收者。eg:[aFraction add: bFraction];执行add: 方法时,self 是作为aFraction 的引用。
super关键字
self 指的是类对象本身,super是父类对象本身,self 用来调用本类对象的方法,super 调用从父类继承下来的方法
在方法中分配和返回对象
以刚刚的add 方法为例进行更改;-(Fraction *) add: (Fraction *) f{
Fraction *result = [[Fraction alloc] init];result.numerator = numerator * f.denominator + denominator * f.numerator;result.denominator = denominator * f.denominator;[result reduce];
return result;
}
该方法直接返回一个类的对象(引用)在 @autoreleasepool 中Fraction *resultFraction;resultFraction = [aFraction add: bFraction];
注意,我们未在main中为resultFraction 创建或者初始化Fraction对象。我们是在add方法中创建初始化Fraction对象的。