你对NSError了解多少?
文章先不要看,先在心里默默回答下这个问题。待会再和文章对比下,看看是否一样。
NSError是什么?
NSError是系统提供的错误类,它继承于NSObject,用于获取系统错误或者自定义错误。它不同于NSExcetion,异常未捕获则会导致程序崩溃。而NSError只是返回一个错误信息,对外部调用者来说可以随意处理这个错误,仅仅是告诉调用者这个方法发生了错误而已。
NSError对象封装了更为丰富,更易扩展的错误信息,你可以只使用错误代码或者错误描述信息。NSError对象的核心属性是错误域(用一个字符串来表示),一个错误域特定的错误代码和用户信息通常都包含在特定的应用程序信息中。
NSError不是一个抽象类,你可以直接使用它。你还可以创建NSError的子类,并且重载localizedDescription方法来提供更好地本地化错误描述信息。
如何使用?
创建对象
- (instancetype)initWithDomain:(NSString *)domain code:(NSInteger)code userInfo:(NSDictionary *)dict NS_DESIGNATED_INITIALIZER; (instancetype)errorWithDomain:(NSString *)domain code:(NSInteger)code userInfo:(NSDictionary *)dict;
获得属性
NSInteger _code; NSString *_domain; NSDictionary *_userInfo;
预定义域
AppKit和Foundation库中主要的错误域
NSString *const NSCocoaErrorDomain;
其他域
NSString *const NSPOSIXErrorDomain; NSString *const NSOSStatusErrorDomain; NSString *const NSMachErrorDomain;
获取本地错误描述
@property (readonly, copy) NSString *localizedDescription; @property (readonly, copy) NSString *localizedFailureReason; @property (readonly, copy) NSString *localizedRecoverySuggestion; @property (readonly, copy) NSArray *localizedRecoveryOptions;
预定义错误Key
/ Key in userInfo. A recommended standard way to embed NSErrors from underlying calls. The value of this key should be an NSError. FOUNDATION_EXPORT NSString *const NSUnderlyingErrorKey; // Keys in userInfo, for subsystems wishing to provide their error messages up-front. FOUNDATION_EXPORT NSString *const NSLocalizedDescriptionKey; // NSString FOUNDATION_EXPORT NSString *const NSLocalizedFailureReasonErrorKey ; // NSString FOUNDATION_EXPORT NSString *const NSLocalizedRecoverySuggestionErrorKey; // NSString FOUNDATION_EXPORT NSString *const NSLocalizedRecoveryOptionsErrorKey ; // NSArray of NSStrings FOUNDATION_EXPORT NSString *const NSRecoveryAttempterErrorKey; // Instance of a subclass of NSObject that conforms to the NSErrorRecoveryAttempting informal protocol FOUNDATION_EXPORT NSString *const NSHelpAnchorErrorKey ; // NSString containing a help anchor // Other standard keys in userInfo, for various error codes FOUNDATION_EXPORT NSString *const NSStringEncodingErrorKey ; // NSNumber containing NSStringEncoding FOUNDATION_EXPORT NSString *const NSURLErrorKey ; // NSURL FOUNDATION_EXPORT NSString *const NSFilePathErrorKey ; // NSString
错误码:
Foundation Constants Reference NSError Codes NSError codes in the Cocoa error domain. enum { NSFileNoSuchFileError = 4, NSFileLockingError = 255, NSFileReadUnknownError = 256, NSFileReadNoPermissionError = 257, NSFileReadInvalidFileNameError = 258, NSFileReadCorruptFileError = 259, NSFileReadNoSuchFileError = 260, NSFileReadInapplicableStringEncodingError = 261, NSFileReadUnsupportedSchemeError = 262, NSFileReadTooLargeError = 263, NSFileReadUnknownStringEncodingError = 264, NSFileWriteUnknownError = 512, NSFileWriteNoPermissionError = 513, NSFileWriteInvalidFileNameError = 514, NSFileWriteInapplicableStringEncodingError = 517, NSFileWriteUnsupportedSchemeError = 518, NSFileWriteOutOfSpaceError = 640, NSFileWriteVolumeReadOnlyError = 642m NSKeyValueValidationError = 1024, NSFormattingError = 2048, NSUserCancelledError = 3072, NSFileErrorMinimum = 0, NSFileErrorMaximum = 1023, NSValidationErrorMinimum = 1024, NSValidationErrorMaximum = 2047, NSFormattingErrorMinimum = 2048, NSFormattingErrorMaximum = 2559, NSPropertyListReadCorruptError = 3840, NSPropertyListReadUnknownVersionError = 3841, NSPropertyListReadStreamError = 3842, NSPropertyListWriteStreamError = 3851, NSPropertyListErrorMinimum = 3840, NSPropertyListErrorMaximum = 4095 NSExecutableErrorMinimum = 3584, NSExecutableNotLoadableError = 3584, NSExecutableArchitectureMismatchError = 3585, NSExecutableRuntimeMismatchError = 3586, NSExecutableLoadError = 3587, NSExecutableLinkError = 3588, NSExecutableErrorMaximum = 3839, } URL Loading System Error Codes These values are returned as the error code property of an NSError object with the domain “NSURLErrorDomain”. typedef enum { NSURLErrorUnknown = -1, NSURLErrorCancelled = -999, NSURLErrorBadURL = -1000, NSURLErrorTimedOut = -1001, NSURLErrorUnsupportedURL = -1002, NSURLErrorCannotFindHost = -1003, NSURLErrorCannotConnectToHost = -1004, NSURLErrorDataLengthExceedsMaximum = -1103, NSURLErrorNetworkConnectionLost = -1005, NSURLErrorDNSLookupFailed = -1006, NSURLErrorHTTPTooManyRedirects = -1007, NSURLErrorResourceUnavailable = -1008, NSURLErrorNotConnectedToInternet = -1009, NSURLErrorRedirectToNonExistentLocation = -1010, NSURLErrorBadServerResponse = -1011, NSURLErrorUserCancelledAuthentication = -1012, NSURLErrorUserAuthenticationRequired = -1013, NSURLErrorZeroByteResource = -1014, NSURLErrorCannotDecodeRawData = -1015, NSURLErrorCannotDecodeContentData = -1016, NSURLErrorCannotParseResponse = -1017, NSURLErrorFileDoesNotExist = -1100, NSURLErrorFileIsDirectory = -1101, NSURLErrorNoPermissionsToReadFile = -1102, NSURLErrorSecureConnectionFailed = -1200, NSURLErrorServerCertificateHasBadDate = -1201, NSURLErrorServerCertificateUntrusted = -1202, NSURLErrorServerCertificateHasUnknownRoot = -1203, NSURLErrorServerCertificateNotYetValid = -1204, NSURLErrorClientCertificateRejected = -1205, NSURLErrorClientCertificateRequired = -1206, NSURLErrorCannotLoadFromNetwork = -2000, NSURLErrorCannotCreateFile = -3000, NSURLErrorCannotOpenFile = -3001, NSURLErrorCannotCloseFile = -3002, NSURLErrorCannotWriteToFile = -3003, NSURLErrorCannotRemoveFile = -3004, NSURLErrorCannotMoveFile = -3005, NSURLErrorDownloadDecodingFailedMidStream = -3006, NSURLErrorDownloadDecodingFailedToComplete = -3007 }
代码示例:
1、获取系统方法错误信息
NSString *fileName = @"fileName"; NSError *error = nil; NSString *string = [[NSString alloc] initWithContentsOfFile:fileName encoding:NSUTF8StringEncoding error:&error]; if (error) { NSLog(@"error is %@",error.description); }else{ NSLog(@"no error"); }
了解C语言的应该都知道,&是取地址的运算符号。
我们可以断点打印下error的相关信息,
(lldb) po error Error Domain=NSCocoaErrorDomain Code=260 "The operation couldn’t be completed. (Cocoa error 260.)" UserInfo=0x7ffad1fc9cb0 {NSFilePath=fileName, NSUnderlyingError=0x7ffad1f13350 "The operation couldn’t be completed. No such file or directory”}
2、自定义错误信息
首先声明我们的错误域常量,错误域通常用域名反写,当然也可以是任何其他字符串。
static NSString * const MyCustomErrorDomain = @“com.awnlab.domain”;
然后声明我们的错误代码,即code错误标识, 自定code可以用枚举(最好用负数, 但不是必须的)
typedef NS_ENUM(NSInteger, MyCustomErrorCodes){ MyCustomErrorCodeTimeout, MyCustomErrorCodeFaild, MyCustomErrorCodeOther, };
自定义错误描述信息
NSDictionary *userInfo = @{NSLocalizedDescriptionKey:@"my custom error desc"};
使用自定义错误
- (void)myError:(NSError **)error { NSDictionary *userInfo = @{NSLocalizedDescriptionKey:@"my custom error desc"}; *error = [NSError errorWithDomain:MyCustomErrorDomain code:MyCustomErrorCodeTimeout userInfo:userInfo]; }
这样调用:
[self myError:&error]; if (error) { NSLog(@"error is %@",error.localizedDescription); }else{ NSLog(@"no error"); }
3、实际应用场景
在NFNetworking中,有这样的方法
AFHTTPRequestOperationManager *manager = [AFHTTPRequestOperationManager manager]; [manager POST:URLString parameters:newParameters success:^(AFHTTPRequestOperation *operation, id responseObject) { } failure:^(AFHTTPRequestOperation *operation, NSError *error) { //失败回调中有NSError的应用,不同的错误信息均通过NSError返回。 }];
其实像我们在编写公用类或框架的时候也应该采用该种方式,将内部不同的错误信息均通过NSError对象返回上层调用者,上层调用者可根据不同的error code进行不同的提示。
NSError的好处、优势
通过NSError在软件组件间传递错误信息。相比简单的错误代码来说,使用NSError的主要优势在于NSError对象包含了错误域属性。
NSError对象的使用并不限于操作系统。就像上面提到的,我们还可以创建自己的NSError对象,使用它们在应用内传递错误消息。
域属性根据产生错误代码的库或框架对这些错误代码进行隔离。借助域,框架开发者无须担心覆盖错误代码,因为域属性定义了产生错误的框架。比如,框架A 与B 都会产生错误代码1,不过这两个错误代码会被每个框架提供的唯一域值进行区分。因此,如果代码需要区分NSError 值,就必须对NSError 对象的code 与domain 属性进行比较。