ios Swift 2:调用可以抛出,但未标有“try”且未处理错误

声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow 原文地址: http://stackoverflow.com/questions/30737262/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me): StackOverFlow

提示:将鼠标放在中文语句上可以显示对应的英文。显示中英文
时间:2020-08-31 06:17:54  来源:igfitidea点击:

Swift 2: Call can throw, but it is not marked with 'try' and the error is not handled

iosxcodeswift

提问by Farhad

After I installed Xcode 7 beta and convert my swift code to Swift 2, I got some issue with the code that I can't figure out. I know Swift 2 is new so I search and figure out since there is nothing about it, I should write a question.

在我安装 Xcode 7 beta 并将我的 swift 代码转换为 Swift 2 后,我遇到了一些我无法弄清楚的代码问题。我知道 Swift 2 是新的,所以我搜索并弄清楚,因为它什么都没有,我应该写一个问题。

Here is the error:

这是错误:

Call can throw, but it is not marked with 'try' and the error is not handled

调用可以抛出,但是没有标记'try'并且错误没有被处理

Code:

代码:

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 _ {
        }

    }

Snapshot:enter image description here

快照:在此处输入图片说明

回答by Mick MacCallum

You have to catch the error just as you're already doing for your save()call and since you're handling multiple errors here, you can trymultiple calls sequentially in a single do-catch block, like so:

您必须像已经为save()调用所做的那样捕获错误,并且由于您在这里处理多个错误,因此您可以try在单个 do-catch 块中按顺序进行多次调用,如下所示:

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

Or as @bames53 pointed out in the comments below, it is often better practice not to catch the error where it was thrown. You can mark the method as throwsthen tryto call the method. For example:

或者正如@bames53 在下面的评论中指出的那样,通常更好的做法是不要在抛出错误的地方捕获错误。您可以将方法标记为throwsthentry来调用该方法。例如:

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

回答by bames53

When calling a function that is declared with throwsin Swift, you must annotate the function call site with tryor try!. For example, given a throwing function:

调用throws在 Swift 中声明为 with 的函数时,必须使用try或注释函数调用站点try!。例如,给定一个抛出函数:

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

this function can be called like:

这个函数可以这样调用:

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

Here we annotate the call with try, which calls out to the reader that this function may throw an exception, and any following lines of code might not be executed. We also have to annotate this function with throws, because this function could throw an exception (i.e., when willOnlyThrowIfTrue()throws, then foowill automatically rethrow the exception upwards.

这里我们用 注释调用try,它告诉读者这个函数可能会抛出异常,并且可能不会执行以下任何代码行。我们还必须用 注释这个函数throws,因为这个函数可能会抛出异常(即,当willOnlyThrowIfTrue()抛出时,然后foo会自动向上重新抛出异常。

If you want to call a function that is declared as possibly throwing, but which you know will not throw in your case because you're giving it correct input, you can use try!.

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

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

This way, when you guarantee that code won't throw, you don't have to put in extra boilerplate code to disable exception propagation.

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

try!is enforced at runtime: if you use try!and the function does end up throwing, then your program's execution will be terminated with a runtime error.

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

Most exception handling code should look like the above: either you simply propagate exceptions upward when they occur, or you set up conditions such that otherwise possible exceptions are ruled out. Any clean up of other resources in your code should occur via object destruction (i.e. deinit()), or sometimes via defered code.

大多数异常处理代码应如下所示:要么在异常发生时简单地向上传播异常,要么设置条件以排除其他可能的异常。代码中其他资源的任何清理都应该通过对象销毁(即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.
}

If for whatever reason you have clean up code that needs to run but isn't in a deinit()function, you can use defer.

如果出于某种原因需要清理需要运行但不在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)
}


Most code that deals with exceptions simply has them propagate upward to callers, doing cleanup on the way via deinit()or defer. This is because most code doesn't know what to do with errors; it knows what went wrong, but it doesn't have enough information about what some higher level code is trying to do in order to know what to do about the error. It doesn't know if presenting a dialog to the user is appropriate, or if it should retry, or if something else is appropriate.

大多数处理异常的代码只是让它们向上传播给调用者,通过deinit()or在途中进行清理defer。这是因为大多数代码不知道如何处理错误;它知道出了什么问题,但它没有足够的信息来说明一些更高级别的代码正在尝试做什么,以便知道如何处理错误。它不知道向用户呈现一个对话框是否合适,或者是否应该重试,或者其他的东西是否合适。

Higher level code, however, should know exactly what to do in the event of any error. So exceptions allow specific errors to bubble up from where they initially occur to the where they can be handled.

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

Handling exceptions is done via catchstatements.

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

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

You can have multiple catch statements, each catching a different kind of exception.

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

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


For more details on best practices with exceptions, see http://exceptionsafecode.com/. It's specifically aimed at C++, but after examining the Swift exception model, I believe the basics apply to Swift as well.

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

For details on the Swift syntax and error handling model, see the book The Swift Programming Language (Swift 2 Prerelease).

有关 Swift 语法和错误处理模型的详细信息,请参阅The Swift Programming Language (Swift 2 Prerelease) 一书