標籤:
首先要注意的是:
“自動引用計數”(Automatic Reference Counting, ARC,參見第30條)在預設情況下不是“異常安全的”(exception safe)。具體來說,這意味著:如果拋出異常,那麼本應在範圍末尾釋放的對象現在卻不會自動釋放了。如果想產生“異常安全”的代碼,可以通過設定編譯器的標誌來實現,不過這將引入一些額外代碼,在不拋出異常時,也照樣要執行這部分代碼。需要開啟的編譯器標誌叫做-fobjc-arc-exceptions。
即使不使用ARC,也很難寫出在拋出異常時不會導致記憶體流失的代碼。
只要發生了可使整個應用程式崩潰的嚴重錯誤時,才應使用異常。異常拋出之後,無須考慮恢複問題,而且應用程式此時也應該退出。這就是說,不用再編寫複雜的“異常安全”代碼了。
在錯誤不那麼嚴重的情況下,可以指派“委託方法”(delegate method)來處理錯誤,也可以把錯誤資訊放在NSError對象裡,經由“輸出參數”返回給調用者。
或令方法返回nil/0以表明其中有錯誤發生。
NSError對象裡封裝了3條資訊:
1、Error domain(錯誤範圍,其類型為字串)
錯誤範圍,也就是產生錯誤的根源,通常用一個特有的全域變數來定義。例:NSURLErrorDomain來表示錯誤範圍。
2、Error code(錯誤碼,其類型為整數)
表明在某一特定的範圍內可能會發生一系列相關錯誤,這些錯誤通常採用enum來定義。
例:HTTP狀態代碼
3、User info(使用者資訊,其類型為字典)
有關些錯誤的額外資訊,其中或許包含一段“本地化的描述”(localized description)。或許還含有導致該錯誤發生的另外一個錯誤,經由此種資訊,可將相關錯誤串成一條“錯誤鏈”(chain of errors)。
NSError經常由“輸出參數”返回給調用者。
例:-(BOOL)doSomething:(NSError**)error
傳遞給方法的參數是個指標,而該指標本身又指向另一個指標,那個指標指向NSError對象。或者也可以把它當成一個直接指向NSError對象的指標。
實際上,在使用ARC時,編譯器會把方法簽名中的NSError** 轉換成NSError* __autoreleasing*,也就是說,指標所指的對象會在方法執行完畢後自動釋放。這個對象必須自己釋放,因為“doSomething:”方法不能保證其調用者可以把此方法中建立的NSError釋放掉,所以必須加入autoreleass。
NSError *error = nil; // 輸出參數
BOOL ret = [object doSomething: &error];
if(error) {
// There was an error
*error = [NSError errorWithDomain:domain code: code userInfo: userInfo]; // *error為error參數“解引用”(dereference)。也就是說,error所指的那個指標現在要指向一個親的NSError對象了。
}
第21條:理解Objective-C錯誤模型