Swift 惯用错误检查

Posted

技术标签:

【中文标题】Swift 惯用错误检查【英文标题】:Swift idiomatic error checking 【发布时间】:2015-06-05 17:05:20 【问题描述】:

假设你有这样一个函数:

func getSomething(error: NSErrorPointer) -> Something

你通常这样使用它:

var error : NSError? = nil
let a = getSomething(&error)

在这里检查错误的惯用方法是什么?更具体的问题:

    如果error == nil 我们可以假设a 永远不会为零,反之亦然 反之亦然? 我们应该首先检查什么:error(对于它的 nilness)或 a(对于 确认它不是零)? a != nil && error != nil 在某些情况下是真的吗?

谢谢!

【问题讨论】:

【参考方案1】:

比较Handling Error Objects Returned From Methods 在《错误处理编程指南》中:

重要提示:成功或失败由 方法。虽然 Cocoa 方法间接返回错误对象 Cocoa 错误域保证返回这样的对象,如果 方法直接返回 nil 或 NO 表示失败,你应该 在尝试之前总是检查返回值是 nil 还是 NO 对 NSError 对象做任何事情。

所以对于 Cocoa/Cocoa Touch 方法,您应该始终检查返回 价值第一。保证error != nil如果方法失败, 但如果方法成功,则不明确保证error == nil

例子:

JSON 序列化

var error : NSError?
if let jsonObj = NSJSONSerialization.JSONObjectWithData(jsonData, options: nil, error: &error) 
    // success
 else 
    // failure
    println("Invalid JSON data: \(error!.localizedDescription)")

核心数据获取请求

var error : NSError?
if let result = context.executeFetchRequest(request, error: &error) 
    // success, result has zero or more elements
 else 
    // failure
    println("Fetch failed: \(error!.localizedDescription)")

复制文件

var error : NSError?
if !NSFileManager.defaultManager().copyItemAtPath(srcPath, toPath: dstPath, error: &error) 
    println("Cannot copy file: \(error!.localizedDescription)")

当然你可以为你自己的函数定义你自己的规则, 但我会遵循相同的 Apple 准则。


更新:从 Swift 2 开始, 产生错误的 Cocoa 方法是 翻译成抛出错误的 Swift 函数,并且这个错误 必须用try-catch处理。这是 Swift 2 版本 以上例子:

JSON 序列化

do 
    let jsonObj = try NSJSONSerialization.JSONObjectWithData(jsonData, options: [])
    // success
 catch let error as NSError 
    // failure
    print("Invalid JSON data: \(error.localizedDescription)")

核心数据获取请求

do 
    let result = try context.executeFetchRequest(request)
    // success, result has zero or more elements
 catch let error as NSError 
    // failure
    print("Fetch failed: \(error.localizedDescription)")

复制文件

do 
    try NSFileManager.defaultManager().copyItemAtPath(srcPath, toPath: dstPath)
 catch let error as NSError 
    print("Cannot copy file: \(error.localizedDescription)")
 

【讨论】:

马丁,感谢您的出色回答!你知道这个逻辑背后的动机是什么吗?为什么要先检查返回值而不是错误? @mikejd:我认为前段时间我听说/读到一个函数可能会将错误指针传递给另一个失败并设置错误的低级函数。如果高层函数选择忽略低层函数的这个错误并返回成功,则仍然设置错误对象。但我不是 100% 确定,而且我还没有真正观察到这种情况。 嗯,这听起来很合理。【参考方案2】:

如果一个函数返回一个可选值,即

func someFunc(someVar: String) -> NSData? 
  // some code

(可选意味着它可以返回一个 nil) 那么错误检查就很简单了

if let data = someFunc("someString") 
  // this means there was NO error as the function didn't return a nil

else 
  // This means there was an error

这个视频是一个很好的参考,可以快速检查和处理错误https://youtu.be/m8szaLqHVDs

【讨论】:

虽然nil 返回值可能是故障的一个很好的提示,但您也经常需要一个实际错误来了解究竟出了什么问题,不是吗? 这取决于并且非常主观。但是如果一个函数提供了 NSError 指针作为参数的可用性,那么你可以选择是否使用它。

以上是关于Swift 惯用错误检查的主要内容,如果未能解决你的问题,请参考以下文章

惯用的节点错误处理

如果成功,从没有结果的函数返回错误的惯用方法是啥?

惯用节点错误处理

在golang中处理逻辑错误与编程错误的惯用方法

合并两种错误类型最惯用的方法是啥?

Swift Alamofire 检查等待超时并放置错误