Swift Error只是個協(xié)議,不能直接使用傳地址的方式傳遞協(xié)議Error
,
他可以通過as
與NSError
互相轉(zhuǎn)化乡范。
public protocol Error {
}
extension Error {
}
extension Error where Self : RawRepresentable, Self.RawValue : FixedWidthInteger {
}
可以發(fā)現(xiàn)什么都沒有暴露出來,但它其實有我們最常用的屬性localizedDescription
。
do {
try functionWhichWillThrow...
// success ↓↓
Statement2...
Statement3...
...
} catch {
// failure ↓↓
print(error.localizedDescription)
}
try..catch 語法和do
配合使用,當try后面的語句執(zhí)行成功后會繼續(xù)執(zhí)行do
代碼塊后面的語句,如果失敗了會執(zhí)行catch
中的代碼塊疏橄,該代碼塊中會攜帶一個名為error
的參數(shù)。你也可以重命名該參數(shù),如下例:
do {
try fucntion...
} catch let err {
print(err.localizedDescription)
}
1. Throw
Swift的錯誤一般通過throw
拋出異常略就,這樣使得代碼更加緊湊捎迫。
1.1 do...catch
do {
let json = try JSONSerialization.jsonObject(with: data, options: .mutableContainers)
print(json)
} catch {
print(error)
}
在OC中一般使用返回值或傳入Error地址將錯誤返回,但Swfit的Error只是協(xié)議表牢,故只有遵循該協(xié)議才能使用原OC的傳遞方式窄绒。
注意:OC Api在Swift中大部分都變更為了throw
的方式,但仍有部分保留該用法崔兴,例如C Api彰导,你仍可以這么做。例如這樣:
func getJson(data: Data, error: inout Error?) {
do {
try JSONSerialization.jsonObject(with: data, options: .mutableContainers)
} catch let err {
error = err
}
}
var error: Error?
getJson(data: Data(), error: &error)
print(error)
通過inout
對傳入的error進行賦值恼布。
1.2 函數(shù)拋出異常
如果你需要拋出異常螺戳,那么你需要在函數(shù)返回值之前添加throws
關(guān)鍵字。
func getJson(data: Data) throws -> Any {
return try JSONSerialization.jsonObject(with: data, options: .mutableContainers)
}
對于有異痴酃可拋出的函數(shù)來說,可以直接傳遞其異常盖腿,也可以手動創(chuàng)建異常爽待,如下:
func getJson(data: Data) throws -> Any {
if data.count == 0 {
throw NSError.init(domain: "", code: 0, userInfo: nil)
// throw NSError.init(domain: "", code: 0, userInfo: nil) as Error
}
return data
}
1.3 重寫throw
函數(shù)
throw
函數(shù)的重寫和普通函數(shù)基本一樣。
class Paper {
func getJson(data: Data) throws -> Any {
if data.count == 0 {
throw NSError.init(domain: "", code: 0, userInfo: nil)
}
return data
}
}
class Book: Paper {
override func getJson(data: Data) throws -> Any {
return try super.getJson(data: data)
}
}
配合閉包返回值翩腐,函數(shù)返回值等鸟款,你可以有各種各樣的
throw
用法。
2. Try
try
和有異常需要拋出的函數(shù)搭配使用茂卦,用法和as
相同:
try | 一般和do...catch 配合使用何什,關(guān)鍵字后面緊跟可能會拋出異常的函數(shù),如果成功則繼續(xù)支撐do 代碼塊后面的語句等龙,失敗則執(zhí)行catch 代碼塊处渣。 |
---|---|
try? | 可以在任何函數(shù)的上下文中使用伶贰,沒有失敗情況,要么成功罐栈,要么返回nil 黍衙,即失敗返回nil ,一般用于不關(guān)心錯誤的情況荠诬。 |
try! | 如果確保try 函數(shù)一定會返回期望值琅翻,添加! 用于強制解包,和as! 同理柑贞。 |
let p = Paper()
let a = try? p.getJson(data: Data()) // Any?
let b = try! p.getJson(data: Data()) // Any
let c = a as! Any // Any
如果傳入的data是有效值方椎,那么a、b钧嘶、c是完全相同的辩尊,try! = try? + as!
,否則使用!
會crash。
3. Error
由于Swift的Error是一個協(xié)議康辑,我們并不能直接創(chuàng)建Error摄欲。
上例中也只是通過NSError
利用as
橋接為Error
類型,當我們需要使用的時候一般需要創(chuàng)建一個類型去實現(xiàn)Error協(xié)議疮薇。
enum MyError: Error {
case network
case jsonSerialization
case server
}
do {
let _ = try getJson(data: data)
} catch let error as MyError {
switch error {
case .jsonSerialization:
print("json 序列化失敗")
case .network:
print("網(wǎng)絡(luò)錯誤")
case .server:
print("服務(wù)器錯誤")
default:
print("未知錯誤")
}
} catch {
}
catch
和elseif
分支一樣胸墙,可以添加多個,用于判斷error類型或者重命名error按咒。
localizedDescription
默認是The operation couldn’t be completed.
,故我們在這里重新定義該屬性的內(nèi)容迟隅。
enum MyError: Error {
case network
case jsonSerialization
case server
case unkown
var localizedDescription: String {
switch self {
case .jsonSerialization:
return "json 序列化失敗"
case .network:
return "網(wǎng)絡(luò)錯誤"
case .server:
return "服務(wù)器錯誤"
default:
return "未知錯誤"
}
}
}
Error不限于enum
,struct
,class
,并且可以根據(jù)自己的需要添加任意屬性励七,比NSError靈活許多智袭。
4. fatalError
fatalError
函數(shù)用于拋出異常,并且攜帶一段信息掠抬,該函數(shù)調(diào)用后一般是crash吼野。
可用于截斷當前上下文的編譯器限制,例如一定要有返回值的場景两波,添加fatalError
及時后面沒有返回值瞳步,也能正常編譯。
func eat(food: String) -> String {
if food == "Apple" {
return "eat an apple"
} else if food == "Banana" {
return "eat a banana"
}
fatalError("不許吃其他水果")
}
eat(food: "Apple") // "eat an apple"
eat(food: "Egg") // Thread 1: Fatal error: 不許吃其他水果
當我們預(yù)料到某些情況一定會發(fā)生錯誤的時候腰奋,但實際使用上一定不會那么使用時单起,可以通過該方式防止編譯器對語法進行檢查,以免我們?nèi)ヌ砑右恍o效代碼去滿足語法劣坊。
或者我們不允許某些我們不想看到的使用場景出現(xiàn)嘀倒,則可以使用該函數(shù),例如:
required init?(coder aDecoder: NSCoder) {
fatalError("init(coder:) has not been implemented")
}
這是系統(tǒng)的默認實現(xiàn),我們必須在這里進行初始化测蘑,或者返回nil
灌危,如果不返回,要么這里需要將所有屬性初始化完畢帮寻,要么fatalError
直接拋出異常乍狐。而這里則選擇的是fatalError
,其實return nil
也可以避免初始化固逗。
class View: UIView {
override class var layerClass: AnyClass {
return AVCaptureVideoPreviewLayer.self
}
var previewLayer: AVCaptureVideoPreviewLayer {
if let layer = self.layer as? AVCaptureVideoPreviewLayer {
return layer
} else {
fatalError("error")
}
}
}
這個例子layer一定是AVCaptureVideoPreviewLayer
類型浅蚪,即if let
語法一定成立,fatalError
被用來打斷編譯器檢查烫罩,其實直接使用as!
也一樣惜傲。