建議大型項目用上Try Catch
我們在平時項目做功能的時候,經常會遇到崩潰的情況。如果是我們在開發測試階段,我們可以找到原因修復。但是遇到已經上線,出現這種問題。要么使用JSPatch
進行熱修復,但是使用熱修復修復苦只有寫的人知道。
本來就是一個方法一個單詞寫錯,一個值沒做異常處理,就要重寫整個方法。對于像我這樣根本不懂JS
語法和不精通JSPatch
的人來說,真的是藍瘦,香菇。
最近寫的項目用Swift
語法進行編寫的,對于之前我們在Object-C
中NSError**
類型的指針標識遇到了什么錯誤,現在轉成Swift
方法直接進行throws
進行拋異常。
這樣我們就必須使用Do Catch
進行捕獲異常了,我覺得蘋果這樣做真的挺好的。
比如我剛剛寫的項目,就用上了,感覺用完頓時高大上了許多。
import Cocoa
enum OFileMagerImportError:Error {
case cannel //點擊了取消的按鈕
case error(message:String)
}
class OFileManger: NSObject {
/*
* 導入配置文件
* return 返回一個數組對象 可能返回為空
*/
class func importAction() throws -> [Any] {
let openPannel = NSOpenPanel()
openPannel.allowedFileTypes = ["ork"]; // 只允許讀取.ork的文件類型
openPannel.allowsMultipleSelection = false // 設置不允許多選
let buttonIndex = openPannel.runModal()
guard buttonIndex == NSFileHandlingPanelOKButton else {
throw OFileMagerImportError.cannel
}
guard openPannel.urls.count > 0 else {
throw OFileMagerImportError.error(message:"你還沒有選擇任何的配置文件!")
}
guard let fileName = openPannel.urls.first else {
throw OFileMagerImportError.error(message:"你還沒有選擇任何的配置文件!")
}
guard let jsonData = try? Data(contentsOf: fileName) else {
throw OFileMagerImportError.error(message:"讀取文件內容失敗!")
}
guard let jsonObj = try? JSONSerialization.jsonObject(with: jsonData, options: .allowFragments) else {
throw OFileMagerImportError.error(message:"配置文件內容不是一個JSON文本!")
}
guard let configList:[Any] = jsonObj as? [Any] else {
throw OFileMagerImportError.error(message:"配置文件內容不是一個數組對象!")
}
return configList
}
}
調用的時候我們可以這么寫。
@IBAction func importAction(_ sender: Any) {
do {
let configList:[Any] = try OFileManger.importAction()
print(configList)
} catch OFileMagerImportError.error(let message) {
OAlertMessage.alert(message: message)
} catch {
print("拋出了其他不給用戶看到的錯誤!")
}
}
我們就可以做一些錯誤的處理。但是只是這樣,我心里面還不是十分強烈想用。
后來線上的App
在雙11那天晚上突然出現打不開崩潰的情況,在外面準備吃飯慶祝的強行喊回去解決問題。
回去覺得應該是那里崩潰了吧,應該也是十分的容易解決。
后來發現因為接口因為最近上線的功能出問題了,就回滾了代碼。導致之前一些接口的字段沒有返回,恰好那個接口沒有用Model
進行映射,所以就出現崩潰了。
經理一直問這個接口回滾好幾天了為啥突然出問題了,原來是接口做了緩存,會根據后臺返回是否需要更新才會重新的請求接口。
雙11那天正好運維更新了數據,導致接口重新請求,少了字段導致崩潰。最后讓后臺強行把拿兩個字段返回,最快的解決問題。
雖然讓后臺加上了字段,但是我覺得我們App
這里沒有做好兼容,才導致這一次事故。幸虧沒影響多久,再說客戶都是外國人,那個時間還沒睡醒。
我們平時遇到的一些崩潰問題所在
- 數組越界
- 給一個可變數組強行賦值不可變,之后當做可變數組用
- 字典值不存在
- 后臺返回的字段不統一,本來有值是字典,沒值是字符串。
導致的崩潰自然不止這些,但是這些占據了崩潰里面大部分,前三個我們可以做一下異常處理,最后一個最好還是讓后臺規范起來,這是長遠之際。或者使用Model
進行映射。
怎么做異常處理
- 做很多
if else
判斷 - 使用
Try catch
進行處理
雖然兩個都要寫很多的代碼,if else
的代碼更加優美一點,但是就怕有一種情況你沒寫出來。覺得最好的辦法還是用try catch
進行。
@try
,@catch
,@throw
,和 @finally
。這四個關鍵詞進行異常處理。
我們看一下常見的一個數組越界的例子:
NSArray *tests = @[];
NSNumber *num = tests[0];
我們不用運行就可以知道這個地方會崩潰,因為我們初始化的數組是空的。但是我們強行取一個元素,導致崩潰。
假設我們現在用上了try catch
的代碼,會如何呢。
NSArray *tests = @[];
@try {
NSNumber *num = tests[0];
} @catch (NSException *exception) {
NSLog(@"%@",exception.userInfo);
} @finally {
NSLog(@"我做一些必須的處理");
}
經過測試,這個代碼會在Debug
的時候斷點,但是強行運行還是可以運行的。但是在Release
發布之后運行完全沒有任何的影響。
雖然我們平時寫代碼上面,不可能讓所有出現異常的地方寫上這樣的代碼。但是對著我們的經驗,我們對于一眼就知道會出崩潰的地方加上,還是能讓線上的應用少出很多問題的。
關于Try catch
的資料可以查看下面資料: