转载

不算“真正的语言”?详说Swift 2.0中的错误处理

【编者按】本文作者Juan Pablo Claude,来自智利首都圣地亚哥,毕业于美国北卡罗莱纳大学教堂山分校(University of North Carolina at Chapel Hill),获化学博士学位,后入阿拉巴马大学伯明翰分校(University of Alabama at Birmingham)任教。2005年底作为Cocoa和Django程序开发人员加入 Big Nerd Ranch 。此前,有过DOS环境下C编程,Windows环境下使用C++编写数据分析应用程序的经历。 译者:白云鹏为移动应用开发者,个人博客: http://baiyunpeng.com 。

译文如下:

苹果公司在今年的全球开发者大会(Worldwide Developers Conference, WWDC)上宣布推出Swift2.0,该语言的首席架构师Chris Lattner表示,Swift 2.0主要在语言基本语法、安全性和格式美观度这三方面进行了改进。除了这些新的功能特性,还有对语法的优化、修饰及美化,最后是Swift 1.x中最具影响力的错误处理机制。

不算“真正的语言”?详说Swift 2.0中的错误处理

这是因为你根本无法回避它。如果打算使用Swift 2.0的话,必须接受错误处理这样的机制,并且错误处理机制将改变Cocoa和Cocoa Touch框架中使用NSError与方法交互的方式。

历史一瞬:不起眼的开端

我们都知道,Swift语言作为Objective-C当前替代语言被推出,是OS X和iOS应用程序开发的“ 通用语 ”。在最初的版本中,Objective-C没有原生的异常处理机制。后来通过添加NSException类,还有 NS_DURING, NS_HANDLER和 NS_ENDHANDLER宏才有了异常处理。这种方案现在被称为“经典的异常处理”,还有这些宏都是基于setjmp()和longjmp()这两个C语言函数的。

异常捕获(exception-catching)看起来如下所示,在NS_DURING和NS_HANDLER宏之间抛出的任何异常都将会导致在NS_HANDLER和NS_ENDHANDLER宏之间执行相应的代码。

NS_DURING     // Call a dangerous method or function that raises an exception:     [obj someRiskyMethod]; NS_HANDLER     NSLog(@"Oh no!");     [anotherObj makeItRight]; NS_ENDHANDLER

下面是立刻能触发抛出异常的方法(现在仍然可用):

- (void)someRiskyMethod {     [NSException raise:@"Kablam"                 format:@"This method is not implemented yet. Do not call!"]; }

可以想象,这种手工处理异常的方式戏弄的是早期Cocoa框架程序开发人员。但是这些程序员还不至于到这份儿上,因为他们很少使用这种方式。无论在Cocoa还是Cocoa Touch框架下,异常通常都被归为灾难性的,不可恢复的错误,比如程序员造成的错误。上面的-someRiskyMethod就是很好的例子,由于实现部分没有准备好而引发了异常。在Cocoa和Cocoa Touch框架中,可恢复的错误由稍后讨论的NSError类来处理。

原生的异常处理

我想由于Objective-C中的经典异常处理机制对应的手工处理方式让人感觉闹心,于是苹果公司在Mac OS X 10.3(2003年10月)中发布了原生的异常处理机制,彼时还没有iOS系统。这本质上是将C++的异常处理嫁接到了Objective-C。异常处理的结构目前看起来是这样的:

@try {  [obj someRiskyMethod]; } @catch (SomeClass *exception) {  // Handle the error.  // Can use the exception object to gather information. } @catch (SomeOtherClass *exception) {  // ... } @catch (id allTheRest) {  // ... } @finally {  // Code that is executed whether an exception is thrown or not.  // Use for cleanup. } 

原生的异常处理使你有机会为每个异常类型指定不同@catch部分。无论@try结果如何,@finally都要执行其对应的代码。

尽管原生的异常处理如所预期的那样抛出一个NSException异常,但是最明确的方法还是“@throw <expression>;”语句。通常你抛出的是NSException实例,但说不定什么对象会被抛出。

NSError

尽管Objective-C原生与经典的异常处理有许多优点,但Cocoa和Cocoa Touch框架应用程序开发人员仍然很少使用异常,而是限制程序出现程序员所导致的不可恢复的错误。使用NSError类处理可恢复的错误,这种方法早于使用异常处理。Swift 1.x也继承了NSError的样式。

在Swift 1.x中,Cocoa和Cocoa Touch的方法和函数可能不会返回一个布尔类型的false或者nil来表示一个失败(failure)的对象。另外,NSErrorPointer对象会被当作一个参数返回特定的失败信息。下面是个典型的例子:

// A local variable to store an error object if one comes back: var error: NSError? // success is a Bool: let success = someString.writeToURL(someURL,  atomically: true,  encoding: NSUTF8StringEncoding,  error: &error) if !success {     // Log information about the error:     println("Error writing to URL: /(error!)") } 

程序员所导致的错误可以用Swift标准库(Swift Standard Library)函数fatalError("Error message”)来标记,将其在控制台记录为错误消息并无条件中止执行。还可以使用assert(), assertionFailure(), precondition()和preconditionFailure()这些函数。

Swift第一次发布时,一些非苹果平台开发人员已经准备好了火把和干草叉。他们声称Swift不能算是“真正的语言”,因为它缺乏异常处理。但是,Cocoa和Cocoa Touch社区对此不予理睬,我们知道NSError和NSException那个时候就存在了。就我个人而言,我相信苹果公司仍然在思考实现错误和异常处理的正确方式。我还认为直到问题解决了,苹果公司才会公开Swift源码。这一切问题在Swift 2.0中全被扫清了。

正文到此结束
Loading...