Swift 2:调用可以抛出,但没有用'try'标记,错误不被处理

在我安装了Xcode 7 beta并将我的Swift代码转换为Swift 2之后,我发现了一些我无法弄清的代码。 我知道斯威夫特2是新的,所以我search和找出,因为没有什么关于它,我应该写一个问题。

这是错误:

调用可以抛出,但没有用“try”标记,并且不处理错误

码:

func deleteAccountDetail(){ let entityDescription = NSEntityDescription.entityForName("AccountDetail", inManagedObjectContext: Context!) let request = NSFetchRequest() request.entity = entityDescription //The Line Below is where i expect the error let fetchedEntities = self.Context!.executeFetchRequest(request) as! [AccountDetail] for entity in fetchedEntities { self.Context!.deleteObject(entity) } do { try self.Context!.save() } catch _ { } } 

快照: 在这里输入图像描述

就像你已经在执行save()调用一样,你必须捕获错误,因为你在这里处理多个错误,你可以在一个do-catch块中顺序地try多个调用,如下所示:

 func deleteAccountDetail() { let entityDescription = NSEntityDescription.entityForName("AccountDetail", inManagedObjectContext: Context!) let request = NSFetchRequest() request.entity = entityDescription do { let fetchedEntities = try self.Context!.executeFetchRequest(request) as! [AccountDetail] for entity in fetchedEntities { self.Context!.deleteObject(entity) } try self.Context!.save() } catch { print(error) } } 

或者@ bames53在下面的评论中指出,通常最好的做法是不要在错误发生的地方发现错误。 您可以将该方法标记为throws然后try调用该方法。 例如:

 func deleteAccountDetail() throws { let entityDescription = NSEntityDescription.entityForName("AccountDetail", inManagedObjectContext: Context!) let request = NSFetchRequest() request.entity = entityDescription let fetchedEntities = try Context.executeFetchRequest(request) as! [AccountDetail] for entity in fetchedEntities { self.Context!.deleteObject(entity) } try self.Context!.save() } 

当调用一个在Swift中用throws声明的函数时,你必须用trytry!来注释函数调用网站try! 。 例如,给定一个抛出函数:

 func willOnlyThrowIfTrue(value: Bool) throws { if value { throw someError } } 

这个函数可以这样调用:

 func foo(value: Bool) throws { try willOnlyThrowIfTrue(value) } 

在这里,我们用try注释调用,调用读者这个函数可能抛出一个exception,并且任何下面的代码行可能不会被执行。 我们也必须用throws来注释这个函数,因为这个函数可能会抛出一个exception(即,当willOnlyThrowIfTrue()抛出时, foo会自动向上抛出exception。

如果你想调用一个被声明为可能抛出的函数,但是你知道这个函数不会抛出你的情况,因为你正在给它正确的input,你可以使用try!

 func bar() { try! willOnlyThrowIfTrue(false) } 

这样,当你保证代码不会抛出,你不需要额外的样板代码来禁止exception传播。

try! 在运行时强制执行:如果使用try! 并且该函数最终会抛出,那么你的程序的执行将会以运行时错误终止。

大多数exception处理代码应该如上所示:要么只是在发生exception时向上传播exception,要么设置条件,否则可能的exception将被排除。 任何清理代码中的其他资源应该通过对象销毁( deinit() ),或者有时通过defer代码来进行。

 func baz(value: Bool) throws { var filePath = NSBundle.mainBundle().pathForResource("theFile", ofType:"txt") var data = NSData(contentsOfFile:filePath) try willOnlyThrowIfTrue(value) // data and filePath automatically cleaned up, even when an exception occurs. } 

如果由于某种原因,你已经清理了需要运行但不在deinit()函数中的代码,你可以使用defer

 func qux(value: Bool) throws { defer { print("this code runs when the function exits, even when it exits by an exception") } try willOnlyThrowIfTrue(value) } 

大多数处理exception的代码只是将它们向上传播给调用者,通过deinit()或者defer方式进行清理。 这是因为大多数代码不知道如何处理错误; 它知道出了什么问题,但是它没有足够的信息来说明某些更高级别的代码试图做什么,以便知道该怎么做。 它不知道是否向用户提供对话框是合适的,或者是否应该重试,或者是否合适。

然而,更高级别的代码应该知道在出现任何错误时应该怎么做。 因此,例外允许特定的错误从最初出现的地方起泡到可以处理的地方。

处理exception是通过catch语句来完成的。

 func quux(value: Bool) { do { try willOnlyThrowIfTrue(value) } catch { // handle error } } 

你可以有多个catch语句,每个catch语句都会捕获一种不同的exception。

  do { try someFunctionThatThowsDifferentExceptions() } catch MyErrorType.errorA { // handle errorA } catch MyErrorType.errorB { // handle errorB } catch { // handle other errors } 

有关例外情况的最佳做法的详细信息,请参阅http://exceptionsafecode.com/ 。 它专门针对C ++,但在检查了Swiftexception模型之后,我相信这些基础知识也适用于Swift。

有关Swift语法和error handling模型的详细信息,请参阅Swift编程语言(Swift 2预发布)一书