Objective-C中的异常——try/catch/throw/finally的使用

0x01 什么是异常

异常指的是程序运行中的意外事件,发生异常后,程序可以创建一个异常对象并执行特定的操作方式。

Objective-C的异常机制和C++的异常机制是兼容的。

Cocoa中使用NSException类来表示异常,我们也可以创建NSException的子类来表达自己的异常。

Cocoa要求所有的异常必须是NSException类型的异常,虽然我们可以通过其他对象来抛出异常,但不会被Cocoa处理!

0x02 处理异常的目的

处理异常的真正目的是处理程序执行中的错误。

Cocoa框架处理错误的方式通常是退出程序,但这肯定不是我们想要的。

为了找出错误的原因,我们应该抛出异常并捕捉异常。

0x03 让Xcode支持异常特性

如果想要使用异常特性,就必须在Xcode 7中开启Enable Objective-C Exceptions项。

选择项目的Build Settrings页,在搜索框中输入关键字exception,可以在编译器LLVM 7.1下拉列表中看到异常特性开关:

 如果关闭异常特性支持,编译器将报错,提示异常特性相关代码不能使用:

0x04 与异常有关的关键字

异常的所有关键字都是以@开头的。

@try {
    // code you want to execute that might throw an exception.
}
@catch (NSException *exception)
{
    // code to execute that handles exception
}
@finally {
    // code that will always be executed. Typically for cleanup.
}

@try

定义用来测试的代码块以决定是否抛出异常,出现异常则捕捉,没有异常则正常运行。

C语言中经常会在异常处理代码中使用setjmp和longjmp语句,但它们不能用于跳出@try代码块,可以用goto和return语句退出异常处理代码。

用@try建立异常检测不会产生性能消耗,但之后捕捉异常却会大量消耗系统资源并影响程序运行速度。

所以在一般的流程中不要使用异常特性。

@catch()

定义用来处理已抛出异常的代码块。

它可接收一个参数,为了确保Cocoa能正常处理异常,我们应该坚持只用NSException对象来抛出异常。

@throw

通知异常的过程通常被称为抛出异常。

通常程序在检测到异常后会抛出异常,但我们可以再次用@throw关键字来通知异常。

在catch()异常处理代码中可以重复抛出异常而无需指定异常对象。

 

@finally

定义无论是否有抛出异常都会被执行的代码块,该段代码始终会被执行。

示例:

//节选Car.m
//...在Car.m中加入异常处理代码

- (void)setTire:(Tire *)tire atIndex:(int)index
{
    @try {
        [tires replaceObjectAtIndex:index withObject:tire];
        //检测数组溢出
    } @catch (NSException *exception) {
        NSLog(@"%@", [exception reason]);
    }

} // setTire:atIndex:

//后面省略Car.m的其他代码...

//--------------------------------------------------------------------------

//main.m

int main(int argc, const char * argv[])
{
    @autoreleasepool 
    {
        Car *car = [[Car alloc] init];
        
        for (int i = 0; i < 6; i++)                  //估计在for循环中让数组索引值溢出
        {
            AllWeatherRadial *tire;
            
            tire = [[AllWeatherRadial alloc] init];
            [car setTire:tire atIndex:i];
            
            [tire release];
        }
        
        Engine *engine = [[Slant6 alloc] init];
        [car setEngine:engine];
        
        [car print];
        [car release];
    }
    return 0;
}

//main.m

//--------------------------------------------------------------------------

//和异常相关的输出结果如下:
//
//-[__NSArrayM replaceObjectAtIndex:withObject:]: index 4 beyond bounds [0 .. 3]
//-[__NSArrayM replaceObjectAtIndex:withObject:]: index 5 beyond bounds [0 .. 3]
//
//...以下省略

0x05 捕捉不同类型的异常

当程序检测到了异常,会创建一个NSException实例来抛出异常。

使用NSException作为捕获条件将捕获所有异常,但我们可以只关注某一类异常。

根据需要处理的异常,我们可以定义多个@catch()代码块,处理代码应该按照从具体到抽象的顺序排序,并在最后使用一个通用的处理代码:

@try{...
} @catch (MyCustomException *custom) {...
} @catch (NSException *exception) {...
} @catch (id value) {...
} @finally {...
}

0x06 异常的内存管理

异常同样也是需要内存管理的,由于现在ARC属性默认开启,所以这里不展开讨论异常的内存管理。

只需按ARC的代码规则编写代码即可。

猜你喜欢

转载自blog.csdn.net/qq_33737036/article/details/81323406