Value Completed Error
错误处理真的很难,比如读取一个文件可能出错,读取成功后,修改内容再去保存可能出错。各种各样的错误都可能发生,使得开发变得很难。
Objective-C 的错误处理
写过 Objective-C 的朋友们都知道,在 Objective-C 中处理错误非常麻烦:
NSError* error;
id json = [NSJSONSerialization JSONObjectWithData: data, options: 0, error: &error];
if (json) {
// 解析成功,继续处理
} else {
// 出现错误,处理 error
}
最重要的逻辑是处理解析 JSON 成功的事情,但考虑到可能出现错误,不得不写很多的代码处理错误。往往可能这种错误处理的代码会写的很多,难以想起最初的逻辑是什么,为此更多时候都会选择忽略错误,直接在 error 参数中传入一个 nil ,以此简化代码的逻辑。
Swift 的错误处理
Swift 在处理错误时,采用了 do catch 的方案。
当然 Objective-C 也有类似的方案,只是根本就没有人用。
在定义一个可能出现错误的方法中加入一个 throws 的标记就可以了。
public class func JSONObjectWithData(data: NSData, options opt: NSJSONReadingOptions) throws -> AnyObject
处理错误的时候代码会写成这个样子:
do {
let json = try NSJSONSerialization.JSONObjectWithData(data, options: NSJSONReadingOptions.AllowFragments)
print(json)
} catch {
print(error)
}相比 Objective-C ,最强大的地方就是可以在这里调用多个可能抛出错误的方法。
do {
let data = try NSData(contentsOfFile: path, options: NSDataReadingOptions())
let json = try NSJSONSerialization.JSONObjectWithData(data, options: NSJSONReadingOptions.AllowFragments)
print(json)
} catch {
print(error)
}从一个文件中读取数据( NSData ),再将其解析成 JSON ,这两个步骤都可能出现错误,幸运的是可以将这些错误统一起来处理,上面两个 try 中错误,都将走到 catch 的闭包中。
然而异步的错误处理呢?
处理异步下的错误情况
仍然是 Alamofire 的例子:
request(.GET, "https://github.com/fluidicon.png")
.responseData { (response) in
switch response.result {
case .Success(let data):
print(data)
case .Failure(let error):
print(error)
// 如何 throws
}
}

又是一个无法完成的事情。Observable 可以很好的完成这件事情。
Observable 处理错误
在进行各种操作变换时,事实上,存在三种场景 Next 、Error 、 Completed,比如在下面这段变换的过程:

其中:

表示传递的值。

表示出现了某种错误(而无法继续)。

表示整个事件流已经结束。
上面这一变换过程描述的是先乘 2 、再用 48 除以该值两个步骤,不幸的是,在最开始传入一个 0 ,会导致错误产生,即除数不能为 0 。
enum ComputeError: ErrorType {
case divisionByZero
}
[3, 4, 0].toObservable()
.map { $0 * 2 }
.map { value -> Int in
guard value != 0 else {
throw ComputeError.divisionByZero
}
return 48 / value
}
.subscribe { event in
switch event {
case .Next(let value):
print("Result: \(value)")
case .Error(let error):
print("Error: \(error)")
case .Completed:
print("completed")
}
}
.addDisposableTo(disposeBag)需要抛出错误就只需要调用 throw ComputeError.divisionByZero ,所有的 error 都会执行到 subscribe 中的 case .Error(let error): 。
一个 Observable 可以传递值、错误、结束三种情况。在异步的处理中也非常轻松,只需要调用观察者( Observer )的 onError 方法,将 error 信息传递下去。
Observable<NSData>.create { (observer) in
let downloadImage = request(.GET, "https://github.com/fluidicon.png")
.responseData { (reponse) in
switch reponse.result {
case .Success(let data):
observer.onNext(data)
case .Failure(let error):
observer.onError(error)
}
observer.onCompleted()
}
return AnonymousDisposable {
downloadImage.cancel()
}
}在请求回调结果回来的时候根据不同的 case ,调用观察者的 onNext 或者 onError 方法。这样一来,错误处理就变得很优雅了,有错误的时候调用 onError 即可。
总结
错误处理自古以来都是一个头疼的事情,很多时候又不得不去处理。特别是异步的错误处理变得异常麻烦,Rx 提供了 onError 的方法,为开发者提供了一个很优雅的错误处理方案。