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

内容来源于 Stack Overflow,并遵循CC BY-SA 3.0许可协议进行翻译与使用

  • 回答 (2)
  • 关注 (0)
  • 查看 (30)

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

这是错误:

调用可以抛出,但没有用'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()处理你的呼叫一样捕获错误,并且由于你在此处理多个错误,因此可以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)
    }
}

通常最好不要在错误发生的地方发现错误。你可以将该方法标记为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()
}
用户回答回答于

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

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!并且函数结束了抛出,那么你的程序的执行将会以运行时错误终止。

大多数异常处理代码应该如上所示:要么只是在发生异常时向上传播异常,要么设置条件以避免可能的异常被排除。任何清理代码中的其他资源都应该通过对象销毁(ie 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语句,每个catch语句都捕获一种不同的异常。

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

扫码关注云+社区