Swift 2: Call 可以抛出,但是没有标记为“ try”,错误也没有得到处理

在我安装了 Xcode 7 beta 并将我的 Swift 代码转换成 Swift 2之后,我在代码方面遇到了一些我无法解决的问题。我知道 Swift 2是新的,所以我搜索并发现既然没有关于它的内容,我应该写一个问题。

这里有一个错误:

Call 可以抛出,但没有标记为“ 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 _ {
}


}

快照: enter image description here

127075 次浏览

您必须像处理 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!注释函数调用站点。例如,给定一个抛掷函数:

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

这个函数可以这样调用:

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

这里我们使用 try对调用进行注释,它向读取器发出这个函数可能会抛出异常,并且可能不会执行以下代码行。我们还必须用 throws对这个函数进行注释,因为这个函数可能抛出异常(也就是说,当 willOnlyThrowIfTrue()抛出异常时,foo将自动向上重新抛出异常。

如果您想要调用一个声明为可能抛出的函数,但是您知道这个函数不会在您的情况下抛出,因为您正在给它提供正确的输入,那么您可以使用 try!

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

这样,当您保证代码不会抛出时,就不必放入额外的样板代码来禁用异常传播。

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

大多数异常处理代码应该类似于上面的代码: 要么只是在异常发生时向上传播异常,要么设置条件以排除其他可能的异常。对代码中其他资源的清理应该通过对象销毁(即 deinit())进行,有时也可以通过 defered 代码进行。

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)
}

大多数处理异常的代码只是将异常向上传播到调用方,并在途中通过 deinit()defer进行清理。这是因为大多数代码不知道如何处理错误; 它知道哪里出错了,但是它没有足够的信息了解某些更高级别的代码正在尝试做什么,以便了解如何处理错误。它不知道向用户显示对话框是否合适,或者是否应该重试,或者是否有其他合适的对话框。

然而,更高级别的代码应该确切地知道在发生任何错误时应该做什么。因此,异常允许特定的错误从它们最初发生的地方冒泡出现,直到它们可以被处理的地方。

异常处理是通过 catch语句完成的。

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

您可以有多个 catch 语句,每个都捕获不同类型的异常。

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

有关带有异常的最佳实践的更多细节,请参见 http://exceptionsafecode.com/。它是专门针对 C + + 的,但是在研究了 Swift 异常模型之后,我相信基本原理也适用于 Swift。

有关 Swift 语法和错误处理模型的详细信息,请参阅书 快速编程语言(快速2预发行版)