1. 理解两种错误处理机制
- Objective - C 异常处理机制:使用
@try
、@catch
、@finally
块。@try
块内放置可能抛出异常的代码,@catch
捕获并处理异常,@finally
块无论是否发生异常都会执行。例如:
@try {
// 可能抛出异常的代码
NSArray *array = @[@"1", @"2"];
NSString *element = array[10]; // 越界访问,会抛出异常
} @catch (NSException *exception) {
NSLog(@"捕获到异常: %@", exception);
} @finally {
NSLog(@"无论是否有异常,都会执行这里");
}
- NSError 设计模式:通过方法的
NSError **
参数返回错误信息。例如:
NSError *error = nil;
NSString *content = [NSString stringWithContentsOfFile:@"nonExistentFile.txt" encoding:NSUTF8StringEncoding error:&error];
if (!content) {
NSLog(@"读取文件失败: %@", error);
}
2. 整体架构层面结合方式
2.1 业务逻辑层
- 轻量级错误:对于业务逻辑中一些相对常见且不影响程序整体运行的错误,优先使用
NSError
。比如网络请求失败、数据解析错误等。例如,在一个网络请求的封装方法中:
- (void)fetchDataWithCompletion:(void(^)(id data, NSError *error))completion {
NSURLSessionDataTask *task = [NSURLSession.sharedSession dataTaskWithURL:[NSURL URLWithString:@"http://example.com/api"] completionHandler:^(NSData * _Nullable data, NSURLResponse * _Nullable response, NSError * _Nullable error) {
if (error) {
completion(nil, error);
return;
}
// 数据解析
NSError *parseError = nil;
id json = [NSJSONSerialization JSONObjectWithData:data options:0 error:&parseError];
if (parseError) {
completion(nil, parseError);
return;
}
completion(json, nil);
}];
[task resume];
}
- 严重错误:对于那些会导致业务逻辑无法继续执行的严重错误,如资源严重不足、关键数据结构损坏等,使用 Objective - C 异常处理机制。例如,在初始化一个核心业务模块时,如果关键配置文件缺失或损坏,抛出异常:
- (instancetype)initWithConfigurationFile:(NSString *)filePath {
@try {
if (![[NSFileManager defaultManager] fileExistsAtPath:filePath]) {
@throw [NSException exceptionWithName:@"ConfigurationFileMissingException" reason:@"关键配置文件缺失" userInfo:nil];
}
// 其他初始化逻辑
self = [super init];
return self;
} @catch (NSException *exception) {
NSLog(@"初始化失败: %@", exception);
return nil;
}
}
2.2 数据持久化层
- 常规错误:数据持久化操作(如数据库插入、更新、删除)中,使用
NSError
处理常见错误,如数据库锁冲突、磁盘空间不足等。以 SQLite 数据库操作为例:
sqlite3_stmt *stmt;
const char *sql = "INSERT INTO users (name, age) VALUES (?,?)";
if (sqlite3_prepare_v2(database, sql, -1, &stmt, NULL) != SQLITE_OK) {
NSError *error = [NSError errorWithDomain:@"SQLiteErrorDomain" code:sqlite3_errcode(database) userInfo:@{NSLocalizedDescriptionKey: [NSString stringWithUTF8String:sqlite3_errmsg(database)]}];
// 处理错误
return NO;
}
// 绑定参数并执行
if (sqlite3_step(stmt) != SQLITE_DONE) {
NSError *error = [NSError errorWithDomain:@"SQLiteErrorDomain" code:sqlite3_errcode(database) userInfo:@{NSLocalizedDescriptionKey: [NSString stringWithUTF8String:sqlite3_errmsg(database)]}];
// 处理错误
sqlite3_finalize(stmt);
return NO;
}
sqlite3_finalize(stmt);
return YES;
- 灾难性错误:如果在数据持久化过程中发生灾难性错误,如数据库文件损坏且无法修复,使用异常处理机制。例如,在数据库迁移过程中,如果发现数据库结构严重损坏:
- (BOOL)migrateDatabase {
@try {
// 检查数据库结构
if (/* 数据库结构严重损坏 */) {
@throw [NSException exceptionWithName:@"DatabaseCorruptionException" reason:@"数据库结构严重损坏,无法迁移" userInfo:nil];
}
// 执行迁移逻辑
return YES;
} @catch (NSException *exception) {
NSLog(@"数据库迁移失败: %@", exception);
return NO;
}
}
2.3 视图层
- 视图加载与交互错误:在视图加载和用户交互相关的错误处理中,使用
NSError
。例如,加载视图控制器的 nib 文件失败:
NSString *nibName = @"MyViewController";
UINib *nib = [UINib nibWithName:nibName bundle:nil];
if (!nib) {
NSError *error = [NSError errorWithDomain:@"ViewLoadingErrorDomain" code:1 userInfo:@{NSLocalizedDescriptionKey: [NSString stringWithFormat:@"无法加载 %@ 的 nib 文件", nibName]}];
// 处理错误,如显示错误提示给用户
return;
}
- 视图相关的严重异常:对于那些导致视图无法正常显示或交互的严重异常,如视图层次结构严重混乱,使用 Objective - C 异常处理机制。例如,在自定义视图的布局方法中,如果发现视图层次结构被严重破坏:
- (void)layoutSubviews {
@try {
if (/* 视图层次结构严重混乱 */) {
@throw [NSException exceptionWithName:@"ViewHierarchyCorruptionException" reason:@"视图层次结构严重混乱,无法布局" userInfo:nil];
}
// 正常布局逻辑
} @catch (NSException *exception) {
NSLog(@"布局失败: %@", exception);
}
}
3. 异常与 NSError 的传播
- NSError 传播:在方法调用链中,将
NSError
从底层向上层传递,让上层调用者决定如何处理错误。例如,数据持久化层的方法返回NSError
,业务逻辑层接收并可能进一步传递给视图层。
// 数据持久化层
- (BOOL)saveData:(id)data error:(NSError **)error {
// 保存逻辑,返回错误
}
// 业务逻辑层
- (BOOL)processAndSaveData:(id)data error:(NSError **)error {
if (![self.dataPersistence saveData:data error:error]) {
return NO;
}
return YES;
}
// 视图层
- (void)saveButtonTapped {
id data = [self getData];
NSError *error = nil;
if (![self.businessLogic processAndSaveData:data error:&error]) {
// 显示错误信息给用户
}
}
- 异常传播:在方法调用链中,如果发生异常,异常会自动向上层传播,直到被
@catch
块捕获。例如,在业务逻辑层抛出的异常,如果在业务逻辑层没有被捕获,会传播到视图层的@try - @catch
块中。
// 业务逻辑层
- (void)doBusinessLogic {
@try {
// 可能抛出异常的代码
if (/* 满足异常条件 */) {
@throw [NSException exceptionWithName:@"BusinessLogicException" reason:@"业务逻辑错误" userInfo:nil];
}
} @catch (NSException *exception) {
// 也可以选择在这里处理异常,或者不处理,让异常继续传播
}
}
// 视图层
- (void)viewDidLoad {
@try {
[self.businessLogic doBusinessLogic];
} @catch (NSException *exception) {
NSLog(@"视图层捕获到业务逻辑异常: %@", exception);
}
}
4. 日志记录与监控
- NSError 日志记录:在处理
NSError
时,记录详细的错误信息到日志中,包括错误域、错误码、错误描述等。可以使用NSLog
或专业的日志框架(如 CocoaLumberjack)。例如:
NSError *error = nil;
// 执行可能产生错误的操作
if (error) {
DDLogError(@"错误域: %@, 错误码: %ld, 错误描述: %@", error.domain, (long)error.code, error.localizedDescription);
}
- 异常日志记录:在
@catch
块中,同样记录异常的详细信息,包括异常名称、原因、用户信息等。例如:
@try {
// 可能抛出异常的代码
} @catch (NSException *exception) {
DDLogError(@"异常名称: %@, 原因: %@, 用户信息: %@", exception.name, exception.reason, exception.userInfo);
}
- 监控:可以使用第三方监控工具(如 Firebase Crashlytics、Bugly 等)来收集和分析异常与
NSError
信息,及时发现系统中的潜在问题。这些工具可以帮助定位错误发生的位置、频率等,以便及时修复。