作者:Erica Sadun,原文鏈接,原文日期:2015/11/5
譯者:pmst;校對:千葉知風(fēng);定稿:numbbbbb
Swift 2 中的try?運(yùn)算符在可選類型(optionals)和錯誤處理機(jī)制中拋出 error 轉(zhuǎn)換為輸出 nil 結(jié)果值之間建立了橋接。這樣你就可以使用 guard 語句和條件綁定,只關(guān)注處理成功的用例(case)。
/// try? 沒有錯誤輸出正確結(jié)果值
/// 有錯誤發(fā)生,輸出nil值
guard let foo = try? somethingThatMayThrow else {
//處理錯誤情況并退出作用域
}
倘若你使用這種方式進(jìn)行錯誤處理,需要注意,它并不會返回 error 信息。本文想說的是:拋棄錯誤信息是一件讓人郁悶的事情!為什么不有選擇地使用try?和try!來自動建立上下文并打印錯誤信息呢?
前陣子,我分享了一個模仿try?語句的基礎(chǔ)實(shí)現(xiàn),可以保留錯誤信息。下面的實(shí)現(xiàn)首先打印返回的錯誤,接著繼續(xù)返回你想要得到的try?的處理結(jié)果:結(jié)果是一個值或 nil。
func attempt<T>(block: () throws -> T) -> Optional<T>{
do { return try block() }
catch { print(error); return nil }
}
這很有效,尤其是當(dāng)你想要進(jìn)一步使用返回值卻發(fā)現(xiàn) guard 語句在失敗時無法返回錯誤信息。使用 attemp 函數(shù)就可以打印錯誤信息。舉個例子,如果我們要使用 NSFileManager 來刪除文件。
NSFileManager.defaultManager().removeItemAtURL(someURL)
你應(yīng)該這樣做:將上述代碼包裹到do-catch的 block 中(略顯冗長),在 attempt 函數(shù)中使用try?,接著處理返回 nil 值的情況,或者使用try!忽視所有錯誤信息(譯者注:倘若實(shí)際有錯誤發(fā)生,程序會直接崩潰,使用它之前你必須確保不會有錯誤產(chǎn)生)。
當(dāng)然這里還有另外一種方式。在文章的最后,我構(gòu)建了一個 attemptFailable 函數(shù),它把 throwing 聲明封裝到 guard/try 的迷你打印系統(tǒng)中,后者會返回一個布爾類型值。下面是使用方法:
if NSFileManager.defaultManager().fileExistsAtPath(myPath) {
guard (attemptFailable{try NSFileManager.defaultManager()
.removeItemAtURL(myURL)}) else {abort()}
}
顯然不是很理想,但是在 playground 中寫一些小東西時相當(dāng)方便,最近我經(jīng)常使用。(Playground 相當(dāng)不錯,作者書籍購買鏈接)。
你可以使用類似的方式增強(qiáng)try!。相比 Swift 的可選值,doOrDie函數(shù)提供了更多信息。就像attemp和attemptFailable函數(shù)一樣,它能夠捕獲上下文,在繼續(xù)使用標(biāo)準(zhǔn)try!終止執(zhí)行前拋出并打印錯誤。
以下是完整代碼:
import Foundation
// 錯誤泛型
public struct Error: ErrorType {let reason: String}
/**
Printing version of try? Call either with standard or autoclosure approach
let contents = attempt{try NSFileManager.defaultManager().contentsOfDirectoryAtPath(fakePath)}
let contents = attempt{try NSFileManager.defaultManager().contentsOfDirectoryAtPath(XCPlaygroundSharedDataDirectoryURL.path!)}
- Returns: Optional that is nil when the called closure throws
*/
public func attempt<T>(source source: String = __FUNCTION__, file: String = __FILE__, line: Int = __LINE__, closure: () throws -> T) -> Optional<T>{
do {
return try closure()
} catch {
let fileName = (file as NSString).lastPathComponent
let report = "Error \(fileName):\(source):\(line):\n \(error)"
print(report)
return nil
}
}
/**
可以打印內(nèi)容并返回布爾值的 try? 可選實(shí)現(xiàn)
let success = attemptFailable{try "Test".writeToFile(fakePath, atomically: true, encoding: NSUTF8StringEncoding)}
- Returns: Boolean 值,如果被調(diào)用的閉包拋出錯誤返回 false,否則返回 true
*/
public func attemptFailable(source source: String = __FUNCTION__, file: String = __FILE__, line: Int = __LINE__, closure: () throws -> Void) -> Bool {
do {
try closure()
return true
} catch {
let fileName = (file as NSString).lastPathComponent
let report = "Error \(fileName):\(source):\(line):\n \(error)"
print(report)
return false
}
}
/**
另外一個包含更多信息的 try! 版本。shouldCrash 是 false 時,即使有錯誤拋出,也會繼續(xù)執(zhí)行
doOrDie(shouldCrash: false, closure: {try "Test".writeToFile(fakePath, atomically: true, encoding: NSUTF8StringEncoding)})
// 或
doOrDie(shouldCrash:false){try NSFileManager.defaultManager().removeItemAtURL(fakeURL)}
// 或
doOrDie{try "Test".writeToFile(fakePath, atomically: true, encoding: NSUTF8StringEncoding)}
*/
public func doOrDie(source: String = __FUNCTION__,
file: String = __FILE__, line: Int = __LINE__, shouldCrash: Bool = true, closure: () throws -> Void) {
let success = attemptFailable(source: source, file: file, line: line, closure: closure)
if shouldCrash && !success {fatalError("Goodbye cruel world")}
}
本文由 SwiftGG 翻譯組翻譯,已經(jīng)獲得作者翻譯授權(quán),最新文章請?jiān)L問 http://swift.gg。