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
声明的函数时,你必须用try
或try!
来注释函数调用网站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预发布)一书 。