??NSError 來對錯(cuò)誤信息進(jìn)行封裝,它主要由3部分內(nèi)容組成:
- domain 錯(cuò)誤發(fā)生域
- code 錯(cuò)誤碼
- userInfo 詳細(xì)信息
??使用NSError對象,除了封裝多種錯(cuò)誤信息,還可以歸檔保存,以及繼承后實(shí)現(xiàn)自定義行為。
Error Domain:
??首先,error domain簡稱錯(cuò)誤域,是一個(gè)字符串。通過 domain 屬性,可以對 error 信息進(jìn)行細(xì)分,domain 可以指明 error 對象代表的錯(cuò)誤具體是發(fā)生在哪一層框架,除了指明層級的 domain,一個(gè)框架或某一模塊的類都可以提供自己相關(guān)錯(cuò)誤的 domain 用于分類,當(dāng)然也包括自己實(shí)現(xiàn)的框架和類。另外,domain 相當(dāng)于對下述代表具體錯(cuò)誤原因的 code 提供了命名空間,避免了 code 的重復(fù)。
??在OS X中將error分為不同的domain。譬如,對于Carbon框架的Error,歸于OSStatus domain(NSOSStatusErrorDomain),對于POSIX error,歸于NSPOSIXErrorDomain,而對于我們的iOS開發(fā),一般使用NSCocoaErrorDomain。NSError.h定義了四個(gè)domain,如下:
// Predefined domain for errors from most AppKit and Foundation APIs.
FOUNDATION_EXPORT NSErrorDomain const NSCocoaErrorDomain;
// Other predefined domains; value of "code" will correspond to preexisting values in these domains.
FOUNDATION_EXPORT NSErrorDomain const NSPOSIXErrorDomain;
FOUNDATION_EXPORT NSErrorDomain const NSOSStatusErrorDomain;
FOUNDATION_EXPORT NSErrorDomain const NSMachErrorDomain;
??除了上述的四個(gè)domain之外,不同的framework定義了自己的domain,比如常見的網(wǎng)絡(luò)請求URL定義了NSURLErrorDomain。
??用戶也可以為自己的framework或者app定義自己的domain,官方推薦的domain命名是:
com.company.framework_or_app.ErrorDomain,例如:com.baidu.baiduMap.errorDomain
code
??NSInteger類型的 code 說明了 domain 下錯(cuò)誤的具體原因。這個(gè)信息對于程序開發(fā)來說極為有用。比如訪問URL資源timeout錯(cuò)誤對應(yīng)的是NSURLErrorTimedOut(-1001)。
iOS開發(fā)中常用的error code所對應(yīng)的頭文件如下:
//Generic Foundation錯(cuò)誤代碼
#import <Foundation/FoundationErrors.h>
#import <CoreData/CoreDataErrors.h>
#import <Foundation/NSURLError.h>
??例如NSURLErrorTimedOut錯(cuò)誤碼就是NSURLError.h庫中的NSURLErrorDomain枚舉code。
userInfo
// 預(yù)定義的userinfo鍵名
NSString *const NSUnderlyingErrorKey; //推薦的標(biāo)準(zhǔn)方式,通用鍵
NSString *const NSLocalizedDescriptionKey; // 詳細(xì)描述鍵
NSString *const NSLocalizedFailureReasonErrorKey; // 失敗原因鍵
NSString *const NSLocalizedRecoverySuggestionErrorKey; //恢復(fù)建議鍵
NSString *const NSLocalizedRecoveryOptionsErrorKey; // 恢復(fù)選項(xiàng)鍵
//其他鍵
NSString *const NSRecoveryAttempterErrorKey;
NSString *const NSHelpAnchorErrorKey;
NSString *const NSStringEncodingErrorKey ;
NSString *const NSURLErrorKey;
NSString *const NSFilePathErrorKey;
??通過 error 對象的 userInfo 字典,可以包含一些其他的自定義信息。NSError類內(nèi)置了幾個(gè)關(guān)于本地化描述錯(cuò)誤的 key,除了根據(jù) key 從 userInfo 中取值外,NSError還提供了對應(yīng)的只讀屬性來直接讀取相關(guān)信息。當(dāng)創(chuàng)建 error 對象時(shí),應(yīng)該在 userInfo 內(nèi)也提供這幾項(xiàng)內(nèi)容。
description
通過屬性localizedDescription獲取 key 為NSLocalizedDescriptionKey中的內(nèi)容,該項(xiàng)是錯(cuò)誤的描述內(nèi)容,可能包含 failure reason。failure reason
通過屬性localizedFailureReason獲取 key 為NSLocalizedFailureReasonErrorKey中的內(nèi)容,該項(xiàng)是錯(cuò)誤原因的解釋。recovery suggestion
通過屬性localizedRecoverySuggestion獲取 key 為
NSLocalizedRecoverySuggestionErrorKey中的內(nèi)容,該項(xiàng)描述了用戶如何操作以修復(fù)錯(cuò)誤。-
recovery options
通過屬性localizedRecoveryOptions獲取 key 為
NSLocalizedRecoveryOptionsErrorKey中的內(nèi)容,該項(xiàng)是一個(gè)字符串?dāng)?shù)組,內(nèi)容是提供給用戶操作的按鈕的標(biāo)題,與 recovery suggestion 配合使用,默認(rèn)的順序規(guī)則是,第一個(gè)字符串應(yīng)該用于最右邊的按鈕,以此類推。
下圖展示了上述幾項(xiàng)屬性的關(guān)系
userInfo關(guān)系 recoveryAttempter
獲取 userInfo 中 key 為NSRecoveryAttempterErrorKey的值,該值是一個(gè)實(shí)現(xiàn)了NSErrorRecoveryAttempting協(xié)議的實(shí)例,與 recovery options 配合使用,可以讓系統(tǒng)根據(jù)用戶選擇點(diǎn)擊的按鈕,執(zhí)行相應(yīng)的修復(fù)方法,但只能在 Cocoa 框架中使用。helpAnchor
獲取 userInfo 中 key 為NSHelpAnchorErrorKey的值,用于 Cocoa 框架中,
NSAlert類執(zhí)行方法+ alertWithError:時(shí),展示的錯(cuò)誤提示框中 help anchor button 的標(biāo)題。
NSError 對象的創(chuàng)建
//兩種初始化方法:其中,domain 不能為空 dict可以為空
- (instancetype)initWithDomain:(NSErrorDomain)domain code:(NSInteger)code userInfo:(nullable NSDictionary<NSErrorUserInfoKey, id> *)dict NS_DESIGNATED_INITIALIZER;
+ (instancetype)errorWithDomain:(NSErrorDomain)domain code:(NSInteger)code userInfo:(nullable NSDictionary<NSErrorUserInfoKey, id> *)dict;
下面寫了一個(gè)自定義的NSError的demo作為參考
NSError+Common.h
#import <Foundation/Foundation.h>
NS_ASSUME_NONNULL_BEGIN
//domain
FOUNDATION_EXPORT NSString *const NSCommonErrorDomain;
/**錯(cuò)誤狀態(tài)碼*/
typedef NS_ENUM(NSInteger,NSCommonErrorCode){
NSCommonErrorCodeUnKnow = -1000,
NSCommonErrorCodeSucc = -1001,
NSCommonErrorCodefailed = -1002,
};
@interface NSError (Common)
+(NSError*)errorCode:(NSCommonErrorCode)code;
+(NSError*)errorCode:(NSCommonErrorCode)code userInfo:(nullable NSDictionary*)userInfo;
@end
NS_ASSUME_NONNULL_END
NSError+Common.m
#import "NSError+Common.h"
NSString *const NSCommonErrorDomain = @"NSCommonErrorDomain";
@implementation NSError (Common)
+(NSError*)errorCode:(NSCommonErrorCode)code{
return [self errorCode:code userInfo:nil];
}
+(NSError*)errorCode:(NSCommonErrorCode)code userInfo:(nullable NSDictionary*)userInfo{
if (userInfo) {
return [NSError errorWithDomain:NSCommonErrorDomain code:code userInfo:userInfo];
}else{
return [NSError errorWithDomain:NSCommonErrorDomain code:code userInfo:
@{
NSLocalizedDescriptionKey:@"返回的消息?",
NSLocalizedFailureReasonErrorKey:@"失敗原因",
NSLocalizedRecoverySuggestionErrorKey:@"意見:恢復(fù)初始化",
@"自定義":@"自定義的內(nèi)容",
}];
}
}
@end
