1.用assert和precondition的方式来抛出错误信息
assert(断言)
断言机制:不符合指定条件就抛出运行时错误,常用于Debug阶段的条件判断
Swift中的assert的使用与OC中的NSAssert类似
oc中的用法
- (void)assertfunction:(NSString *)email password :(NSString *)password {
NSAssert(email.length < 8, @"invalid email");
NSAssert(password.length < 8, @"invalid password");
}
swift中的用法
func assertfunction(email: String ,password: String) {
assert(email.count < 8, "invalid email")
assert(password.count < 8, "invalid password")
}
precondition
precondition为Swift独有(OC没有),使用方式与assert一样,第一个参数填写判断的条件第二个是message.Swift中precondition的作用与assert类似,最大的区别在于assert只能在debug模式下使用,而precondition在debug模式和Release模式下都能够起作用.
precondition(condition: Bool, message: String)
2. 使用try catch处理异常
先看一下OC中的try catch
- (void)trycatchfunction {
@try {
NSArray<NSString*> *list = @[];
NSLog(@"list[1]===%@",list[1]);
} @catch (NSException *exception) {
NSLog(@"%@",exception.description);
} @finally {
}
}
oc中的try catch,会将try中的异常捕获,然后会执行catch中的代码,Swift中的try catch步骤要多一些分为三步
1. 自定义错误
Swift可以通过Error协议自定义运行时的错误信息,这里我们使用枚举来举例
enum RequestError :Error {//注意Swift的所有异常类型都继承于Error。
case netError
case serviceError
case missingParameter(parameter: String)
case isnil
}
2. 抛出自定义Error
func throwErrors(type :Int) throws -> String {//(在可能会抛出异常的函数声明时必须加上关键字throws)
if type == 1 {
throw RequestError.netError (//函数内部通过throw来抛出自定义Error)
}else if type == 2 {
throw RequestError.serviceError
}else if type == 3 {
throw RequestError.missingParameter(parameter: "password")
}
return "success"
}
3.捕获异常(catch)
do {
let errorMsg = try throwErrors(type: 2) //当调用可能会抛出Error的函数时需要使用关键字try
//不抛出Error会继续执行下面的代码,如果抛出Error后,try下一句直到作用域结束的代码都将停止运行
print(errorMsg)
// let array : [Int] = []
// 如果执行 print(array[2])程序会崩溃,swift中的try catch 只能捕获事先定义好的异常,这点与OC有很大不同
} catch {
//报错则执行相对应的错误类型
switch error {//这里要特别说明一下swift的error是异常,与OC中的NSError不是一回事,与OC中的NSException相似
case RequestError.netError :
print("是网络错误")
case RequestError.serviceError :
print("是服务端错误")
default:
print("缺少参数")
}
}
4.处理Error的两种方式
- 使用do-catch捕捉Error
func findOptionsError(value :String?) throws -> [String] {
guard let value = value else {
throw RequestError.isnil
}
return [value]
}
do {
try findOptionsError(value: nil)
} catch let error {
print(error)
}
- 不捕捉Error
let value = try findOptionsError(value: nil)
//如果有其他的函数调用这个函数
func test() throws {
try findOptionsError(value: nil)//这里的Error会自动抛给上层函数,如果层层上报,一直到main函数,依然没有捕捉Error,那么程序就会Crash
}
let value = try? findOptionsError(value: nil)//此处异常会返回一个nil
let crash = try! findOptionsError(value: nil)//此处会崩溃
try try? try!的区别
try : 执行函数后,如果有异常需要catch异常,如果不catch,则会抛给上层函数,如果最终还是没有处理则程序crash
try? :是可选性的执行,不报错的时候返回正常的值.如果有异常会返回一个nil,程序不会crash.
try! :是强制解包,当抛出异常的时候也解包,导致崩溃问题。
rethrows
rethrows表明函数本身并不会抛出错误,但是调用它的闭包参数(函数参数)会抛出错误,那么他会将错误上抛.我们写一个类似于系统的faltMap函数来举例.
func transform( _ num :Int) throws -> String {
return "\(num)"
}
func flatMap (array :[Int]) throws -> [String] {
var result :[String] = []
for element in array {
result.append( try transform(element))
}
return result
}
flatMap这个函数本身是不会抛出错误的,但是因为调用了transform 这个可能抛出错误的函数,所以需要使用 throws,将错误上报 ,接下来我们把transform函数变成faltMap的一个闭包参数,将这两个函数合并成一个函数
func flatMap(array : [Int] ,_ transform : (Int) throws -> String) throws -> [String] {
var result :[String] = []
for element in array {
result.append( try transform(element))
}
return result
}
_ = flatMap(array: [1,2,3]) { (num) -> String in
return "\(num)"
}
这样调用新的flatMap和调用之前的faltMap达到的效果就一致了.接下来我们再做一点改动 将最后的throws换成 rethrows
func flatMap(array : [Int] ,_ transform : (Int) throws -> String) rethrows -> [String] {
var result :[String] = []
for element in array {
result.append( try transform(element))
}
return result
}
在这里将throws 换成rethrows有两个好处
- 告诉调用者函数的参数中有可能会抛出错误的闭包参数.
- 将throws替换成rethrows后,调用这个函数时不需要再使用关键字try,可以直接调用
5.defer语句
defer语句:用来定义以任何方式(抛错误,return等)离开代码前必须要执行的代码 defer语句将延迟至当前作用域结束之前执行
func judgeValuable( _ passWord :String?) throws {
guard let passWord = passWord else {
throw RequestError.isnil
}
print("passWord is ",passWord)
}
func saveThePassword(_ passWord:String?) throws {
defer {
print("已经检验过密码")
}
try? judgeValuable(passWord)
}
try saveThePassword(nil)
//isnil
//已经检验过密码
defer语句的执行顺序与定义顺序相反
func fn1() {print("fn1") }
func fn2() {print("fn2") }
func fn3() {print("fn3") }
func testDefer() {
defer {
fn1()
}
defer {
fn2()
}
defer {
fn3()
}
}
testDefer()
//fn3
//fn2
//fn1
3. fatalError
如果遇到严重的问题时,希望结束程序运行,可以直接使用fatalError函数抛出错误(这种错误无法通过do catch捕获),一旦调用程序就会终止.
func pay(amount :Int) -> Bool {
if amount > 0 && amount < 10000 {
return true
}
fatalError("金额超出范围")
}
pay(amount: 100000)//程序会直接终止
相关的swift 代码在 这里.如果有疑问可以看一下.
iOS的报错和捕获异常先说这么多,如果有错误希望大家指出.欢迎评论.