通过向Swift添加ErrorType
,现在可以更清晰,更简洁的方式表达错误和失败事件。我们不再将iOS开发人员绑定到NSError
的旧方式,笨拙且难以使用。
ErrorType
很有用,原因如下:
然而,我最近遇到了一些问题,尤其是一个问题,我很想知道别人如何解决这个问题。
比如说,您构建了一个类似于Facebook的社交网络应用程序,并且您拥有Group
模型。当用户首次加载您的应用程序时,您希望执行两件/三件事:
在整个过程中,您可以将错误类型分为两个不同的类别:PersistenceError
和NetworkError
符合ErrorType
的枚举可能看起来像
enum PersistenceError: ErrorType {
case CreateFailed([String: AnyObject)
case FetchFailed(NSPredicate?)
}
enum NetworkError: ErrorType {
case GetFailed(AnyObject.Type) // where AnyObject is your Group model class
}
您可以使用多种方式/设计模式来传递错误。最常见的当然是try / catch。
func someFunc() throws {
throw .GetFailed(Group.self)
}
这里,因为抛出的函数还不能指定它们抛出的错误类型,虽然我怀疑它会改变,但你可以轻松地抛出NetworkError
或{{1} }。
当使用更通用或功能性的方法时会出现问题,例如ReactiveCocoa或Result。
PersistenceError
然后包装两个电话:
func fetchGroupsFromRemote() -> SignalProducer<[Group], NetworkError> {
// fetching code here
}
func fetchGroupsFromLocal() -> SignalProducer<[Group], PersistenceError> {
// fetch from local
}
标记为func fetch() -> SignalProducer<Group, ???> {
let remoteProducer = self.fetchGroupsFromRemote()
.flatMap(.Concat) ) { self.saveGroupsToLocal($0) // returns SignalProducer<[Group], PersistenceError> }
let localProducer = self.fetchGroupsFromLocal()
return SignalProducer(values: [localProducer, remoteProducer]).flatten(.Merge)
}
的地点出现了什么错误类型?是???
还是NetworkError
?您不能使用PersistenceError
因为它不能用作具体类型,如果您尝试将其用作通用约束ErrorType
,编译器仍会抱怨说它期望类型为<E: ErrorType>
的参数列表。
所以问题变得越来越少,使用try / catch以及功能方法更是如此,如何维护错误层次结构,以便在不同E
一致性的同时保留错误信息,同时仍然具有描述性错误api
到目前为止我能想到的最好的是:
ErrorType
基本上是一个长错误枚举,因此任何和所有错误都是相同的类型,甚至最深的错误也可以在链中传播。
其他人如何处理此问题?我喜欢有一个通用错误枚举的好处,但可读性和api澄清受到影响。我更倾向于让每个函数描述他们返回的特定错误集群,而不是让每个函数返回enum Error: ErrorType {
// Network Errors
case .GetFailed
// Persistence Errors
case .FetchFailed
// More error types
}
但是,我再也看不到如何做到这一点而不会丢失错误信息。< / p>
答案 0 :(得分:1)
只是尝试解决您的问题,可能不是一个完美的解决方案。使用协议轻松传递错误对象:
//1.
protocol Error {
func errorDescription()
}
//2.
enum PersistenceError: ErrorType, Error {
case CreateFailed([String: AnyObject)
case FetchFailed(NSPredicate?)
func errorDescription() {
}
}
//3.
enum NetworkError: ErrorType, Error {
case GetFailed(AnyObject.Type) // where AnyObject is your Group model class
func errorDescription() {
}
}
//5.
func fetch() -> SignalProducer<Group, Error> {
...
}