Swift--错误处理

do-try-catch错误处理模式

Swift2.x抛弃了cocoa的错误处理模式,使用了do-try-catch错误处理模式

cocoa的错误处理模式

let contents = NSString(contentsOfFile: filePath, encoding: NSUTF8StringEncoding, error: nil)

或者
var err: NSError?

let contents = NSString(contentsOfFile: filePath, encoding: NSUTF8StringEncoding, error: err)

由于Objective-C和Swift1.x没有强制处理机制,因此一旦真的发生错误,程序就会崩溃

do-try-catch错误模式

do {
    let str = try NSString(contentsOfFile: filePath, encoding: NSUTF8StringEncoding)

} catch let err as NSError {
    print(err.description)
}

: do-tyr-catch这种错误模式与Java中异常处理机制非常类似,本意就是尝试( try )做一件事情,如果失败则捕获( catch )处理

捕获错误

完整的do-try-catch错误处理模式语法如下:
do {
try 语句
成功处理语句组
} catch 匹配错误 {
错误处理语句组
}

错误类型

在Swift中错误类型必须遵从Error Type协议,其次是考虑错误类型的匹配,它应该设计为枚举类型,因为枚举类型非常适合将一组相关值关联起来。

enum DAOError: Error {
    case NOData
    case PrimaryKeyNull
}

do {
    //try 访问数据表函数或方法
} catch DAOError.NOData {
    print("没有数据。")
}catch DAOError.PrimaryKeyNull {
    print("主键为空。")
}
在函数或方法中抛出错误
  • 在函数或方法中通过throw语句人为地抛出错误
  • 在函数或方法中调用其他可以抛出错误的函数或方法,但是没有捕获处理,会导致错误被传播出来

//删除Note 方法
func remove(model: Note) throws {
    guard let date = model.data else {
        //抛出“主键为空”错误
        throw DAOError.PrimaryKeyNull
    }

    //比较日期主键是否相等
    for (index, note) in listData.enumerate() where note.date == date     {
        listData.removeIndex(index)
    }
}

//查询所有数据方法
func findAll() throws -> [Note] {
    guard listData.count > 0 else {
        //抛出“没有数据”错误
        throw DAOError.NoData
    }
  return listData
}

func printNotes() throws {
    let datas = try findAll()
    for note in datas {
        print("data: \(note.date!) - content:\(note.content!)")
    }
}

try printNotes()

1、remove方法我们声明为有可能发生错误,加了个throws, 如果 let date = model.date 成立的话,走for语句,否则抛出异常“ throw DAOError.PrimaryKeyNull”,跳出程序代码。
2、findAll方法我们声明为有可能发生错误,加了个throws, 有返回值[Note],如果“listData.count > 0” 成立,返回listData,否则抛出异常。
3、printNotes方法我们声明为有可能发生错误,加了个throws。
方法内部调用findAll方法,即在printNotes方法中调用了可以抛出错误的findAll方法,所以前面要加try,但却没有用catch捕获处理这个错误,一旦发生错误,捕获不到错误,方法不会继续往下走,跳出方法,往下传播,传播它的上层调用者,把错误给上层调用者,上层调用者还是处理不了的话,在往下传,最后传到运行环境,然后崩溃。

4、调用“try printNotes()” ,会调用printNotes方法, 调用printNotes方法又会调用findAll方法,如果findAll方法中有错误发生的情况下,错误传递给findAll方法,findAll方法又会传递给printNotes方法,然后再传递给“try printNotes”。如果“try printNotes”也不捕获的话就会传递给运行环境,运行环境遇到错误后就会崩掉。

对错误进行捕获和处理,并不是所有的函数和方法都有这个必要性,有的是没有这个必要性的,所以只能往上传播给它的调用者。有的函数和方法是需要捕获并处理的

比如一些权限的问题,有人有必要有能力来处理这个错误,把错误抛给他,他来处理。比如有些错误是给用户看的,有些是给管理员看的,如果是给用户看的错误要抛给表示层(view, viewController),如果是给系统管理员看的,直接打印日志,存到数据库里,或发个邮件就可以了。

声明抛出错误

能放到try后面调用的函数或方法都是有要求的,它们是有可能抛出错误,但你要在这些函数或方法声明的参数后面加上throws关键字,表示这个函数或方法可以抛出错误。

示例:

//删除Note记录的方法
func remove(model: Note) throws {
        ...
}

//查询所有记录数据的方法
func findAll() throws -> [Note] {
        ...
}
try? 和 try!的使用区别

1、使用try

try?会将错误转换为可选值,当调用try? + 函数或方法语句时,如果函数或方法抛出错误,程序不会崩溃,而是返回一个nil; 如果没有抛出错误,则返回可选值。

func findAll() throws -> [Note] {
    guard listData.count > 0 else {
        //抛出“没有数据”错误
        throw DAOError.NoData
    }
    return listData
}

 let datas = try? findAll()

  print(datas)

2、使用try!

使用try!可以打破错误传播链条。错误抛出后被传播者捕获,这样就形成了一个传播链条,有时我们确实不想让错误传播下去,这时便可以使用try!语句。

//查询所有数据方法
func findAll() throws -> [Note] {
    guard listData.count > 0 else {
        //抛出“没有数据”错误
        throw DAOError.NoData
    }
    return listData
}

func printNotes() {
    let datas = try! findAll()
    for note in datas {
        print("data: \(note.date!) - content:\(note.content!)")
    }
}

printNotes()
最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
【社区内容提示】社区部分内容疑似由AI辅助生成,浏览时请结合常识与多方信息审慎甄别。
平台声明:文章内容(如有图片或视频亦包括在内)由作者上传并发布,文章内容仅代表作者本人观点,简书系信息发布平台,仅提供信息存储服务。

友情链接更多精彩内容