Swift 2:Call可以抛出,但没有标记为'尝试'并且不处理错误

时间:2015-06-09 16:03:17

标签: ios xcode swift

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

以下是错误:

  

通话可以抛出,但没有标记为'尝试'而错误不是   处理

代码:

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

2 个答案:

答案 0 :(得分:154)

你必须抓住错误就像你已经为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()
}

答案 1 :(得分:38)

调用在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())或有时通过defer ed代码进行。

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语法和错误处理模型的详细信息,请参阅书籍The Swift Programming Language (Swift 2 Prerelease)