Objective-C:设值/取值方法、参数设置、self关键字、继承、动态绑定、NSObject基本方法、异常处理

Objective-C代码的一般组成:

@interface部分描述类和类的方法(声明)

exp:

@interface Fraction: NSObject
-(void) print;
-(void) setNumerator: (int)n;
-(void) setDenominator: (int)d;
@end

声明方法时,-表示为实例方法,+表示为类方法;如果有返回值则将返回类型放入-/+后的括号中;如果有接受参数,则方法名以冒号结束,后接内含参数类型的括号和参数名。

 

 

@implementation部分描述数据,并实现接口中声明方法的实际代码(定义)

exp:

@implementation Fraction {
    int numerator;
    int denominator;
}
-(void) print {
    NSLog (@"%i/%i", numerator, denominator);
}
-(void) setNumerator:(int)n {
    numerator = n;
}
-(void) setDenominator:(int)d {
    denominator = d;
}
@end

类名与@interface部分名称相同,指定需要存储的数据类型及名称及实现@implementation中的方法。

 

@program部分的程序代码实现程序预期目的

int main(int argc, char *argv[]) {
    @autoreleasepool {
        Fraction *myFraction;
        myFraction = [Fraction alloc]; //分配存储空间
        myFraction = [myFraction init]; //初始化
//可组合为:Fraction *myFraction = [[Fraction alloc] init];
//也可用new将alloc和init操作结合:Fraction *myFraction = [Fraction new];
        
        [myFraction setNumerator: 1];
        [myFraction setDenominator: 3];
        
        NSLog(@"The value of my Fraction is: ");
        [myFraction print];
    }
    return 0;
}

也可在interface和implementation部分为类声明实例变量。

 

 

按照约定类名一般以大写字母开头,实例变量、对象及方法一般以小写字母开头。

 

Id数据类型:一般对象类型,可存储任何类型的对象。

 

基础数据类型和限定词表

double-%g输出,%lf读入

前缀f、l、u、ll用来明确表示常量是float、long、unsigned和long long类型。

 

运算中的类型转换

整数变量运算中数字的所有小数部分将丢失,如int a=25, b = 2,a/b=12及int i2=-150, i2/100=-1。

将浮点值赋值给整形变量,所有小数部分将丢失,如float f1=123.125,,int i1=f1,i1=123。

类型转换运算符(如(float))是一元运算符,不会影响变量的值。(int)将浮点值转换为整数,舍去其中的小数部分。

赋值运算符op=优先级低于除逗号运算符外的所有运算符,所以a /= b + c相当于a = a / (b + c)。

 

去除Xcode时间戳

 

#ifdef DEBUG
#define NSLog(FORMAT, ...) fprintf(stderr,"%s\n",[[NSString stringWithFormat:FORMAT, ##__VA_ARGS__] UTF8String]);
#else
#define NSLog(...)
#endif

 

 

优先级:!运算符=一元运算符>二元算术运算符或关系运算符 > &&运算符 > ||运算符>条件与算符>赋值运算符、逗号运算符

 

条件运算符从右到左结合。

Xcode支持条件运算符的ANSI扩展语句:condition ?: expression

逻辑上等价为condition?condition:expression,对condition求值,若为true则返回值为condition,若为false则返回值为expression。

 

Objective-C中内置Boolean变量BOOL类型,预定义值YES和NO。

 

设值方法(setter):设置实例变量值的方法;

取值方法(getter):检索实例变量值的方法;

设值方法和取值方法通常称为访问器(accessor)方法

Objective-C 2.0提供自动生成设值和取值方法。首先在接口部分(如:Fraction.h)中添加@property指令:

 

#import <Foundation/Foundation.h>
@interface Fraction : NSObject
@property int numerator, denominator;
-(void) print;
-(double) convertToNum;
@end

 

在实现部分(如Fraction.m)中添加@synthesize指令:

#import "Fraction.h"
@implementation Fraction {
    int numerator;
    int denominator;
}
@synthesize numerator, denominator;
-(void) print {
    NSLog(@"%i/%i", numerator, denominator);
}
-(double) convertToNum {
    if(denominator != 0)
        return (double)numerator/denominator;
    else
        return NAN;
}
@end

也可不使用@synthesize指令,仅使用@property指令完成,但编译器自动生成的实例变量会以(_)字符作为名称首个字符。

 

Objective-C支持使用点运算符访问属性。如:

myFraction.numerator 等价于 [myFraction numerator]

instance.property = value 等价于 [instance setProperty: value]

点运算符也支持对自定义的方法使用。

 

设置具有多个参数的方法,如

[myFraction setNumerator: 1 andDenominator: 3]或[myFraction setTo:1 over:3]

在接口文件Fraction.h添加声明:

-(void) setTo: (int)n over: (int) d;

在实现文件Fraction.m添加方法定义:

-(void) setTo:(int)n over:(int)d {
    numerator = n;
    denominator = d;
}

在测试程序main.m中声明实例并调用[myFraction setTo:1 over:3] 即可。

也可不对所有参数都设置参数,如(第二个参数没有命名):

[aFraction set:100 : 200];

在接口文件Fraction.h添加声明:

-(void) set: (int)n : (int) d;

在实现文件Fraction.m添加方法定义:

-(void) set:(int)n :(int)d {
    numerator = n;
    denominator = d;
}

声明传入参数为该类对象的函数时,应注意参数声明带(*),说明参数是该类对象的一个引用。如,为Fraction类编写add方法:

在接口文件Fraction.h添加声明:

-(void) add: (Fraction *)f;

在实现文件Fraction.m添加方法定义:

-(void) add:(Fraction *)f {
    numerator = numerator*f.denominator+denominator*f.numerator;
    denominator = denominator*f.denominator;
}

在测试程序main.m中声明实例并调用

[aFraction add:bFraction];

 

局部静态变量可的声明通常放置在implementation文件开始处(所有方法声明外部),这样所有实例或类方法都可以访问它们。如:

#import “Printer.h”
static int pageCount;
@implementation Printer
…
@end

 

self关键字可用于指明对象是当前方法的接收者,是当前对象的引用。如“在add方法中编写[self reduce]使收到add消息的Fraction对象自动约简。

可创建一个返回值为Fraction的新的add方法。在接口文件Fraction.h添加声明:

-(Fraction *) add: (Fraction *)f;

在实现文件Fraction.m添加方法定义:

-(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;
}

在测试程序main.m中声明实例并调用

resultFraction = [aFraction add:bFraction];

resultFraction最终保存了一个Fraction的对象引用,该对象是在add:方法中创建并通过方法返回的。

 

继承

为了使子类能够直接访问到需要使用的实例变量,需要先在接口部分@interface声明。如果实例变量在实现部分声明和合成(synthesize)则是私有的,子类不能直接访问,需要明确定义或合成取值方法((.)或[])才能访问。

子类继承父类的所有方法和实例变量,类的每个实例拥有自己的实例变量。

在接口部分,如果编译器需要了解另一个自定义的实例变量的类,可以导入头文件(如:#import “XYPoint.h”),也可以使用指令@class XYPoint;使用@class指令提高了效率,因为编译器不需要引入和处理整个XYPoint.h文件,只需要知道XYPoint是一个类名。

在实现部分,@class指令是不够的,因为编译器需要更多的消息。

覆写方法:定义一个同名的新方法,使用和父类相同的名称定义的方法代替或覆写了继承的定义,新方法必须具有相同的返回类型和参数数目。

抽象(abstract)类/抽象超类(abstract superclass):在该类中定义方法和实例变量,目的在于让使用者更容易创建子类,但不期望任何人从这个类创建实例。

 

 

多态:使不同的类共享相同方法名称的能力。允许开发一组类,这组类中每一个类都能响应相同的方法名,每个类的定义都封装了响应特定方法所需的代码,使其独立于其他的类定义。多态还允许以后添加新的类,这些新类也能够响应相同的方法名。

将一个变量定义为特定类的对象时使用的是静态类型,静态指对存储在变量中的对象的类型进行显示声明,存储在这种形态中的对象的类是预定义(静态)的。

动态类型绑定:Objective-C系统总是跟踪对象所属的类,先判定对象所属的类,然后在运行时(不是编译时)确定需要动态调用的方法。

id数据类型:一种通用的对象类型,可以用来存储任何类的对象。声明为id对象类型的变量可以用来保存不同类型的对象。

id dataValue;
Fraction *f1 = [[Fraction alloc] init];
Complex *c1 = [[Complex alloc] init];
[f1 setTo:2 over:5];
[c1 setReal:10.0 andImaginary:2.5];
dataValue = f1;
[dataValue print];
dataValue = c1;
[dataValue print];

注意:id对象类型的声明没有使用星号。不能为id变量使用点运算符。

原因:动态类型绑定。在发送消息给id对象时,先检查id对象中存储的对象所属的类,然后在运行时(不是编译时,存储在id变量中的对象类型在编译时无法确定)确定需要动态调用的方法。

使用动态类型调用方法时,需要注意如果在多个类中实现名称相同的方法,每个方法必须符合各个参数的类型和返回值类型,编译器才能为消息表达式生成正确的代码。

 

NSObject类所支持的一些基本方法

 

发送class消息可以根据类名或另一个对象生成一个类对象

[Square class]; //从名为Square的类中获得类对象
[mySquare class]; //mySquare是一个实例,查看它所属的类
if ([obj1 class] == [obj2 class]); //查看存储在变量obj1和obj2中的对象是不是相同的类实例
[myFraction isMemberOfClass: [Fraction class]]; 测试变量myFract是不是Fraction类的实例

selector是一个SEL类型的值,可以由一个方法名应用@selector指令生成。如:

@selector (alloc) //为alloc方法生成一个selector,该方法是从NSObject类继承的
@selector (setTo:over:) //为setTo:over:方法生成一个selector,该方法是在Fraction类中实现的(注意方法名称中的冒号字符)
[Fraction instancesRespondToSelector: @selector(setTo:over:)] //测试Fraction类的实例是否相应setTo:over方法(包括继承的方法,并不只测试直接定义在类中的方法)

performSelector:方法及其变体允许向对象发送消息,这条消息可以使存储在变量中的selector。如:

SEL action;
Id graphicObject;
…
action = @selector(draw);
…
[graphicObject performSelector: action]; /*发送SEL变量action所指定的方法到存储在graphicObject中的任何图形对象*/

 如果需要先确定对象是否可以响应这个动作:

/*respondsToSelector:判断是否可以将时间的处理委托给你的方法,如果没有实现这个方法,它会按照定义的默认行为自己处理该事件*/
if ([graphicObject respondsToSelector: action] == YES)
    [graphicObject performSelector: action];
else
    //错误处理代码

例:

int main(int argc, char *argv[]) {
    @autoreleasepool {
        Square *mySquare = [[Square alloc] init];
        
        // isMemberOf:测试类中的直接成员关系
        if([mySquare isMemberOfClass:[Square class]] == YES) //yes
            NSLog(@"mySquare is a member of Square class");
        if([mySquare isMemberOfClass:[Rectangle class]] == YES) //no
            NSLog(@"mySquare is a member of Rectangle class");
        if([mySquare isMemberOfClass:[NSObject class]] == YES) //no
            NSLog(@"mySquare is a member of NSObject class");
        
        // isKindOf:检测继承层次中的关系
        if([mySquare isKindOfClass:[Square class]] == YES) //yes
            NSLog(@"mySqaure is a kind of Square");
        if([mySquare isKindOfClass:[Rectangle class]] == YES) //yes
            NSLog(@"mySquare is a kind of Rectangle");
        if([mySquare isKindOfClass:[NSObject class]] == YES) //yes 检测Square类是否响应alloc类方法
            NSLog(@"mySquare is a kind of NSObject");
        
        // respondsTo:
        if([mySquare respondsToSelector:@selector(setSide:)] == YES) //yes
            NSLog(@"mySquare responds to setSide: method");
        if([mySquare respondsToSelector:@selector(setWidth:andHeight:)] == YES) //yes
            NSLog(@"mySquare responds to setWidth:andHeight: method");
        if([Square respondsToSelector:@selector(alloc)] == YES) //yes
            NSLog(@"Square class responds to alloc method");
        
        // instancesResondTo
        if([Rectangle instancesRespondToSelector:@selector(setSide:)] == YES) //no
            NSLog(@"Instances of Rectangle respond to setSide: method");
        if([Square instancesRespondToSelector:@selector(setSide:)] == YES) //yes
            NSLog(@"Instances of Square respond to setSide: method");
        if([Square isSubclassOfClass:[Rectangle class]] == YES) //yes
            NSLog(@"Square is a subclass of a rectangle");
    }
    return 0;
}

 

使用@try处理异常

 

@try {
            [f noSuchMethod];
        }
        @catch(NSException *exception) {
            NSLog(@"Caught %@%@", [exception name], [exception reason]);
        }
        NSLog(@"Execution continues!");
    }

 

当@try块抛出异常时,@catch块被执行,包含异常信息的NSException对象作为参数传递给@catch块,name方法检索异常的名称,reason方法给出原因。在@catch块中最后一条语句执行后,程序会立即继续执行之后的语句。

可使用@throw;指令抛出特定的异常。

可使用多个@catch块按顺序捕获并处理各种异常。

 

posted @ 2017-10-13 14:54  丹尼尔奥利瓦  阅读(937)  评论(0编辑  收藏  举报