在循環中處理錯誤時,首次 error 返回 domain: nil 導致 !error 為 false,進而跳過預期邏輯;後續迭代則正常返回 nil。本文剖析 Objective-C/Swift 錯誤處理機制,揭示「假 nil」本質,提供穩健判斷模式。
// 錯誤示範
NSError *error = nil;
for (int i = 0; i < 3; i++) {
[self doSomethingWithError:&error];
if (!error) { // 首次 error.domain == nil 但 error != nil,判斷失效!
// 預期邏輯未執行
}
error = nil; // 重置
}
誤區:以為 error == nil 等價於「無錯誤」。實則 NSError* 是指針,可能指向一個 domain == nil 的實例對象(非空指針)。
NSError 對象但未正確設置 domain/code/userInfo,導致 domain = nil 但對象本身存在。NSError ** 參數傳遞時,調用者負責初始化為 nil,被調用者決定是否創建對象。若被調用者邏輯分支覆蓋不全,可能留下「半初始化」對象。Error 協議類型桥接到 NSError 時,若原始錯誤類型不符合預期,可能產生異常對象。// 模式 1:雙重檢查(推薦)
NSError *error = nil;
if ([self doSomethingWithError:&error]) {
// 成功:方法返回 YES,error 保證為 nil
} else if (error) { // error != nil
// 失敗:檢查 domain/code 確認具體錯誤
if (error.domain && [error.domain isEqualToString:NSCocoaErrorDomain]) { ... }
} else {
// 異常:方法返回 NO 但 error 為 nil(不規範實現)
}
// 模式 2:Swift 原生錯誤處理(現代項目首選)
do {
try someThrowingFunction()
// 成功
} catch let error as NSError {
// 處理 NSError
} catch {
// 處理其他 Error 協議類型
}
BOOL 且帶 NSError** 的方法,必須遵循契約:成功返回 YES 且 error = nil;失敗返回 NO 且 error != nil 且 error.domain != nil。error.domain 非空。throws 機制,編譯期強制處理,消除運行時判斷歧義。