在Swift中添加ErrorType
後,現在可以用更簡潔,更簡潔的方式表示錯誤和失敗事件。我們不再像iOS開發者那樣受到NSError
的老方法的束縛,很難使用。Swift - 錯誤傳播,同時保持api清晰度
- 函數通用參數
- 任何enum能夠符合並實施
- 與閉鎖/扔範式
工作更好:
ErrorType
的幾個原因是偉大的然而,最近我遇到了一些問題和特別的問題,我很好奇看到其他人如何解決這個問題。
舉例來說,您將構建一個類似於Facebook的社交網絡應用程序,並且您有Group
模型。當用戶第一次加載你的應用程序時,你想做兩三件事:
- 從你的服務器獲取相關組。
- 獲取磁盤上已存在的組(Realm,CoreData等)
- 使用剛剛獲取的遠程副本更新本地副本。
在這個過程中,你可以打破的錯誤類型分爲兩個不同的類別: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
或PersistenceError
。
使用更通用或功能性方法(例如ReactiveCocoa或Result)時會遇到麻煩。
然後包裹在兩個電話:
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>
,編譯器仍會抱怨說它需要E
類型的參數列表。
所以這個問題變得不那麼嚴重,對於try/catch更是如此,對於函數式方法更是如此,如何維護一個錯誤層次結構,以便錯誤信息可以保留在不同的ErrorType
一致性中,同時仍然存在描述性錯誤api。
我能想出迄今最好的是:
enum Error: ErrorType {
// Network Errors
case .GetFailed
// Persistence Errors
case .FetchFailed
// More error types
}
這基本上是一個長的錯誤枚舉使任何和所有的錯誤都是同一類型的,甚至最深的錯誤可以傳播了鏈。
其他人如何處理這個問題?我喜歡有一個通用錯誤枚舉的好處,但可讀性和api澄清受到影響。我寧願讓每個函數描述它們返回的具體錯誤集羣,而不是每個函數都返回Error
,但是我再也看不到如何在不丟失錯誤信息的情況下如何做到這一點。
這當然是一個很好的解決方案。不幸的是,它仍然存在同樣的問題,即任何返回錯誤類型的函數或方法都將是'Error'類型。 – barndog
正確,但即使類型是Error,它實際上是具有baseclass指針的子類對象。您可以根據協議方法的子類型實現獲取動態行爲。可能是我沒有準確地獲取上下文,但是您還可以通過向ErrorType添加擴展方法來改善行爲,並將其與任何自定義子類類型無縫地使用。 – Tushar