- 异常情况(Exceptions)
- 注意:异常处理只有 Mac OS X 10.3 以上才支持。
- 基于 "Programming in Objective-C," Copyright © 2004 by Sams Publishing一书中的范例,并经过允许而刊载。
- CupWarningException.h
- 异常情况(Exceptions)
§ #import <Foundation/NSException.h>
§
§ @interface CupWarningException: NSException
@end
- CupWarningException.m
§ #import "CupWarningException.h"
§
§ @implementation CupWarningException
@end
- CupOverflowException.h
§ #import <Foundation/NSException.h>
§
§ @interface CupOverflowException: NSException
@end
- CupOverflowException.m
§ #import "CupOverflowException.h"
§
§ @implementation CupOverflowException
@end
- Cup.h
§ #import <Foundation/NSObject.h>
§
§ @interface Cup: NSObject {
§ int level;
§ }
§
§ -(int) level;
§ -(void) setLevel: (int) l;
§ -(void) fill;
§ -(void) empty;
§ -(void) print;
@end
- Cup.m
§ #import "Cup.h"
§ #import "CupOverflowException.h"
§ #import "CupWarningException.h"
§ #import <Foundation/NSException.h>
§ #import <Foundation/NSString.h>
§
§ @implementation Cup
§ -(id) init {
§ self = [super init];
§
§ if ( self ) {
§ [self setLevel: 0];
§ }
§
§ return self;
§ }
§
§ -(int) level {
§ return level;
§ }
§
§ -(void) setLevel: (int) l {
§ level = l;
§
§ if ( level > 100 ) {
§ // throw overflow
§ NSException *e = [CupOverflowException
§ exceptionWithName: @"CupOverflowException"
§ reason: @"The level is above 100"
§ userInfo: nil];
§ @throw e;
§ } else if ( level >= 50 ) {
§ // throw warning
§ NSException *e = [CupWarningException
§ exceptionWithName: @"CupWarningException"
§ reason: @"The level is above or at 50"
§ userInfo: nil];
§ @throw e;
§ } else if ( level < 0 ) {
§ // throw exception
§ NSException *e = [NSException
§ exceptionWithName: @"CupUnderflowException"
§ reason: @"The level is below 0"
§ userInfo: nil];
§ @throw e;
§ }
§ }
§
§ -(void) fill {
§ [self setLevel: level + 10];
§ }
§
§ -(void) empty {
§ [self setLevel: level - 10];
§ }
§
§ -(void) print {
§ printf( "Cup level is: %i\n", level );
§ }
@end
- main.m
§ #import "Cup.h"
§ #import "CupOverflowException.h"
§ #import "CupWarningException.h"
§ #import <Foundation/NSString.h>
§ #import <Foundation/NSException.h>
§ #import <Foundation/NSAutoreleasePool.h>
§ #import <stdio.h>
§
§ int main( int argc, const char *argv[] ) {
§ NSAutoreleasePool *pool = [[NSAutoreleasePool alloc] init];
§ Cup *cup = [[Cup alloc] init];
§ int i;
§
§ // this will work
§ for ( i = 0; i < 4; i++ ) {
§ [cup fill];
§ [cup print];
§ }
§
§ // this will throw exceptions
§ for ( i = 0; i < 7; i++ ) {
§ @try {
§ [cup fill];
§ } @catch ( CupWarningException *e ) {
§ printf( "%s: ", [[e name] cString] );
§ } @catch ( CupOverflowException *e ) {
§ printf( "%s: ", [[e name] cString] );
§ } @finally {
§ [cup print];
§ }
§ }
§
§ // throw a generic exception
§ @try {
§ [cup setLevel: -1];
§ } @catch ( NSException *e ) {
§ printf( "%s: %s\n", [[e name] cString], [[e reason] cString] );
§ }
§
§ // free memory
§ [cup release];
§ [pool release];
}
- output
§ Cup level is: 10
§ Cup level is: 20
§ Cup level is: 30
§ Cup level is: 40
§ CupWarningException: Cup level is: 50
§ CupWarningException: Cup level is: 60
§ CupWarningException: Cup level is: 70
§ CupWarningException: Cup level is: 80
§ CupWarningException: Cup level is: 90
§ CupWarningException: Cup level is: 100
§ CupOverflowException: Cup level is: 110
CupUnderflowException: The level is below 0
- NSAutoreleasePool 是一个内存管理类别。现在先别管它是干嘛的。
- Exceptions(异常情况)的丢出不需要扩充(extend)NSException 对象,你可简单的用 id 来代表它: @catch ( id e ) { ... }
- 还有一个 finally 区块,它的行为就像 Java 的异常处理方式,finally 区块的内容保证会被呼叫。
- Cup.m 里的 @"CupOverflowException" 是一个 NSString 常数物件。在 Objective-C 中,@ 符号通常用来代表这是语言的衍生部分。C 语言形式的字符串(C string)就像 C/C++ 一样是 "String constant" 的形式,型别为 char *。
- 继承、多型(Inheritance, Polymorphism)以及其它对象导向功能
- id 型别
- Objective-C 有种叫做 id 的型别,它的运作有时候像是 void*,不过它却严格规定只能用在对象。Objective-C 与 Java 跟 C++ 不一样,你在呼叫一个对象的 method 时,并不需要知道这个对象的型别。当然这个 method 一定要存在,这称为 Objective-C 的讯息传递。
- 基于 "Programming in Objective-C," Copyright © 2004 by Sams Publishing一书中的范例,并经过允许而刊载。
- Fraction.h
- id 型别
§ #import <Foundation/NSObject.h>
§
§ @interface Fraction: NSObject {
§ int numerator;
§ int denominator;
§ }
§
§ -(Fraction*) initWithNumerator: (int) n denominator: (int) d;
§ -(void) print;
§ -(void) setNumerator: (int) d;
§ -(void) setDenominator: (int) d;
§ -(void) setNumerator: (int) n andDenominator: (int) d;
§ -(int) numerator;
§ -(int) denominator;
@end
- Fraction.m
§ #import "Fraction.h"
§ #import <stdio.h>
§
§ @implementation Fraction
§ -(Fraction*) initWithNumerator: (int) n denominator: (int) d {
§ self = [super init];
§
§ if ( self ) {
§ [self setNumerator: n andDenominator: d];
§ }
§
§ return self;
§ }
§
§ -(void) print {
§ printf( "%i / %i", numerator, denominator );
§ }
§
§ -(void) setNumerator: (int) n {
§ numerator = n;
§ }
§
§ -(void) setDenominator: (int) d {
§ denominator = d;
§ }
§
§ -(void) setNumerator: (int) n andDenominator: (int) d {
§ numerator = n;
§ denominator = d;
§ }
§
§ -(int) denominator {
§ return denominator;
§ }
§
§ -(int) numerator {
§ return numerator;
§ }
@end
- Complex.h
§ #import <Foundation/NSObject.h>
§
§ @interface Complex: NSObject {
§ double real;
§ double imaginary;
§ }
§
§ -(Complex*) initWithReal: (double) r andImaginary: (double) i;
§ -(void) setReal: (double) r;
§ -(void) setImaginary: (double) i;
§ -(void) setReal: (double) r andImaginary: (double) i;
§ -(double) real;
§ -(double) imaginary;
§ -(void) print;
§
@end
- Complex.m
§ #import "Complex.h"
§ #import <stdio.h>
§
§ @implementation Complex
§ -(Complex*) initWithReal: (double) r andImaginary: (double) i {
§ self = [super init];
§
§ if ( self ) {
§ [self setReal: r andImaginary: i];
§ }
§
§ return self;
§ }
§
§ -(void) setReal: (double) r {
§ real = r;
§ }
§
§ -(void) setImaginary: (double) i {
§ imaginary = i;
§ }
§
§ -(void) setReal: (double) r andImaginary: (double) i {
§ real = r;
§ imaginary = i;
§ }
§
§ -(double) real {
§ return real;
§ }
§
§ -(double) imaginary {
§ return imaginary;
§ }
§
§ -(void) print {
§ printf( "%_f + %_fi", real, imaginary );
§ }
§
@end
- main.m
§ #import <stdio.h>
§ #import "Fraction.h"
§ #import "Complex.h"
§
§ int main( int argc, const char *argv[] ) {
§ // create a new instance
§ Fraction *frac = [[Fraction alloc] initWithNumerator: 1 denominator: 10];
§ Complex *comp = [[Complex alloc] initWithReal: 10 andImaginary: 15];
§ id number;
§
§ // print fraction
§ number = frac;
§ printf( "The fraction is: " );
§ [number print];
§ printf( "\n" );
§
§ // print complex
§ number = comp;
§ printf( "The complex number is: " );
§ [number print];
§ printf( "\n" );
§
§ // free memory
§ [frac release];
§ [comp release];
§
§ return 0;
}
- output
§ The fraction is: 1 / 10
The complex number is: 10.000000 + 15.000000i
- 这种动态连结有显而易见的好处。你不需要知道你呼叫 method 的那个东西是什么型别,如果这个对象对这个讯息有反应,那就会唤起这个 method。这也不会牵涉到一堆繁琐的转型动作,比如在 Java 里呼叫一个整数对象的 .intValue() 就得先转型,然后才能呼叫这个 method。
- 继承(Inheritance)
- 基于 "Programming in Objective-C," Copyright © 2004 by Sams Publishing一书中的范例,并经过允许而刊载。
- Rectangle.h
§ #import <Foundation/NSObject.h>
§
§ @interface Rectangle: NSObject {
§ int width;
§ int height;
§ }
§
§ -(Rectangle*) initWithWidth: (int) w height: (int) h;
§ -(void) setWidth: (int) w;
§ -(void) setHeight: (int) h;
§ -(void) setWidth: (int) w height: (int) h;
§ -(int) width;
§ -(int) height;
§ -(void) print;
@end
- Rectangle.m
§ #import "Rectangle.h"
§ #import <stdio.h>
§
§ @implementation Rectangle
§ -(Rectangle*) initWithWidth: (int) w height: (int) h {
§ self = [super init];
§
§ if ( self ) {
§ [self setWidth: w height: h];
§ }
§
§ return self;
§ }
§
§ -(void) setWidth: (int) w {
§ width = w;
§ }
§
§ -(void) setHeight: (int) h {
§ height = h;
§ }
§
§ -(void) setWidth: (int) w height: (int) h {
§ width = w;
§ height = h;
§ }
§
§ -(int) width {
§ return width;
§ }
§
§ -(int) height {
§ return height;
§ }
§
§ -(void) print {
§ printf( "width = %i, height = %i", width, height );
§ }
@end
- Square.h
§ #import "Rectangle.h"
§
§ @interface Square: Rectangle
§ -(Square*) initWithSize: (int) s;
§ -(void) setSize: (int) s;
§ -(int) size;
@end
- Square.m
§ #import "Square.h"
§
§ @implementation Square
§ -(Square*) initWithSize: (int) s {
§ self = [super init];
§
§ if ( self ) {
§ [self setSize: s];
§ }
§
§ return self;
§ }
§
§ -(void) setSize: (int) s {
§ width = s;
§ height = s;
§ }
§
§ -(int) size {
§ return width;
§ }
§
§ -(void) setWidth: (int) w {
§ [self setSize: w];
§ }
§
§ -(void) setHeight: (int) h {
§ [self setSize: h];
§ }
@end
- main.m
§ #import "Square.h"
§ #import "Rectangle.h"
§ #import <stdio.h>
§
§ int main( int argc, const char *argv[] ) {
§ Rectangle *rec = [[Rectangle alloc] initWithWidth: 10 height: 20];
§ Square *sq = [[Square alloc] initWithSize: 15];
§
§ // print em
§ printf( "Rectangle: " );
§ [rec print];
§ printf( "\n" );
§
§ printf( "Square: " );
§ [sq print];
§ printf( "\n" );
§
§ // update square
§ [sq setWidth: 20];
§ printf( "Square after change: " );
§ [sq print];
§ printf( "\n" );
§
§ // free memory
§ [rec release];
§ [sq release];
§
§ return 0;
}
- output
§ Rectangle: width = 10, height = 20
§ Square: width = 15, height = 15
Square after change: width = 20, height = 20
- 继承在 Objective-C 里比较像 Java。当你扩充你的 super class(所以只能有一个 parent),你想自订这个 super class 的 method,只要简单的在你的 child class implementation 里放上新的实作内容即可。而不需要 C++ 里呆呆的 virtual table。
- 这里还有一个值得玩味的地方,如果你企图像这样去呼叫 rectangle 的 constructor: Square *sq = [[Square alloc] initWithWidth: 10 height: 15],会发生什么事?答案是会产生一个编译器错误。因为 rectangle constructor 回传的型别是 Rectangle*,而不是 Square*,所以这行不通。在某种情况下如果你真想这样用,使用 id 型别会是很好的选择。如果你想使用 parent 的 constructor,只要把 Rectangle* 回传型别改成 id 即可。