macOS 错误处理
错误码处理
1. 检查 API 返回值
所有 API 调用都应该检查返回值:
objc
// 检查引擎创建
FBEngineConfig *config = [[FBEngineConfig alloc] init];
config.appId = @"your_app_id";
config.appKey = @"your_app_key";
self.engine = [FBBeautyEffectEngine createEngineWithConfig:config];
if (self.engine == nil) {
NSLog(@"Failed to create beauty engine");
return;
}
// 检查美颜类型启用
int ret = [self.engine setBeautyTypeEnabled:FBBeautyType_Basic enabled:YES];
if (ret == 0) {
NSLog(@"Successfully enabled basic beauty");
} else {
NSLog(@"Failed to enable basic beauty, error code: %d", ret);
}
// 检查参数设置
int ret = [self.engine setBasicParam:FBBeautyParam_Smoothing floatValue:0.5f];
if (ret != 0) {
NSLog(@"Failed to set smoothing param, error code: %d", ret);
}2. 常见错误码
根据 API 文档,主要错误码:
- 0: 成功
- -1: 引擎未初始化
objc
@interface BeautyErrorHandler : NSObject
@end
@implementation BeautyErrorHandler
+ (void)handleError:(int)errorCode operation:(NSString *)operation {
switch (errorCode) {
case 0:
NSLog(@"%@ succeeded", operation);
break;
case -1:
NSLog(@"%@ failed: Engine not initialized", operation);
break;
default:
NSLog(@"%@ failed: Unknown error code %d", operation, errorCode);
break;
}
}
@end处理图像数据
1. 输入图像验证
objc
@interface ImageValidator : NSObject
+ (BOOL)validateImageFrame:(FBImageFrame *)imageFrame;
@end
@implementation ImageValidator
+ (BOOL)validateImageFrame:(FBImageFrame *)imageFrame {
if (imageFrame == nil) {
NSLog(@"ImageFrame is nil");
return NO;
}
// 检查图像尺寸
int width = imageFrame.width;
int height = imageFrame.height;
if (width <= 0 || height <= 0) {
NSLog(@"Invalid image dimensions: %dx%d", width, height);
return NO;
}
// macOS 可以支持更大的图像
if (width > 8192 || height > 8192) {
NSLog(@"Image too large: %dx%d", width, height);
return NO;
}
return YES;
}
@end2. 图像处理错误处理
objc
@interface ImageProcessor : NSObject
@property (nonatomic, strong) FBBeautyEffectEngine *engine;
@end
@implementation ImageProcessor
- (FBImageFrame *)processImageSafely:(FBImageFrame *)input {
// 验证输入
if (![ImageValidator validateImageFrame:input]) {
return nil;
}
@try {
// 处理图像
FBImageFrame *output = [self.engine processImage:input processMode:FBProcessModeVideo];
if (output == nil) {
NSLog(@"Failed to process image: output is nil");
return nil;
}
return output;
} @catch (NSException *exception) {
NSLog(@"Exception during image processing: %@", exception.reason);
return nil;
}
}
@end3. 内存管理
objc
@interface SafeImageProcessor : NSObject
@property (nonatomic, strong) FBBeautyEffectEngine *engine;
@end
@implementation SafeImageProcessor
- (BOOL)processImageSafe:(FBImageFrame *)input output:(FBImageFrame *)output {
FBImageFrame *result = nil;
@try {
// 处理图像
result = [self.engine processImage:input processMode:FBProcessModeVideo];
if (result == nil) {
NSLog(@"Processing returned nil");
return NO;
}
// 复制结果到输出
[self copyImageFrame:result to:output];
return YES;
} @catch (NSException *exception) {
NSLog(@"Exception during processing: %@", exception.reason);
return NO;
}
}
- (void)copyImageFrame:(FBImageFrame *)src to:(FBImageFrame *)dst {
// 实现图像复制逻辑
FBImageBuffer *srcBuffer = [src toRGBA];
FBImageBuffer *dstBuffer = [dst toRGBA];
if (srcBuffer != nil && dstBuffer != nil) {
const uint8_t *srcData = [srcBuffer data];
uint8_t *dstData = (uint8_t *)[dstBuffer data];
if (srcData != nil && dstData != nil) {
memcpy(dstData, srcData, MIN(srcBuffer.size, dstBuffer.size));
}
}
}
@end日志和文件操作
1. 日志配置错误处理
objc
@interface LogConfigHandler : NSObject
+ (BOOL)configureLogging:(BOOL)enableConsole
enableFile:(BOOL)enableFile
logFilePath:(NSString *)logFilePath;
@end
@implementation LogConfigHandler
+ (BOOL)configureLogging:(BOOL)enableConsole
enableFile:(BOOL)enableFile
logFilePath:(NSString *)logFilePath {
@try {
FBLogConfig *logConfig = [[FBLogConfig alloc] init];
logConfig.consoleEnabled = enableConsole;
logConfig.fileEnabled = enableFile;
logConfig.level = FBLogLevel_Info;
if (enableFile && logFilePath != nil && logFilePath.length > 0) {
// 检查目录是否存在
NSString *logDir = [logFilePath stringByDeletingLastPathComponent];
NSFileManager *fileManager = [NSFileManager defaultManager];
if (![fileManager fileExistsAtPath:logDir]) {
NSError *error = nil;
if (![fileManager createDirectoryAtPath:logDir
withIntermediateDirectories:YES
attributes:nil
error:&error]) {
NSLog(@"Failed to create log directory: %@", error.localizedDescription);
return NO;
}
}
logConfig.fileName = logFilePath;
}
int ret = [FBBeautyEffectEngine setLogConfig:logConfig];
return ret == 0;
} @catch (NSException *exception) {
NSLog(@"Failed to configure logging: %@", exception.reason);
return NO;
}
}
@end2. 文件写入错误处理
objc
@interface FileWriteHandler : NSObject
+ (BOOL)saveImageBuffer:(FBImageBuffer *)buffer toPath:(NSString *)filePath;
@end
@implementation FileWriteHandler
+ (BOOL)saveImageBuffer:(FBImageBuffer *)buffer toPath:(NSString *)filePath {
if (buffer == nil) {
NSLog(@"ImageBuffer is nil");
return NO;
}
NSFileManager *fileManager = [NSFileManager defaultManager];
NSString *dir = [filePath stringByDeletingLastPathComponent];
// 创建目录
if (![fileManager fileExistsAtPath:dir]) {
NSError *error = nil;
if (![fileManager createDirectoryAtPath:dir
withIntermediateDirectories:YES
attributes:nil
error:&error]) {
NSLog(@"Failed to create directory: %@", error.localizedDescription);
return NO;
}
}
// 写入文件
const uint8_t *data = [buffer data];
NSData *nsData = [NSData dataWithBytes:data length:buffer.size];
NSError *error = nil;
BOOL success = [nsData writeToFile:filePath options:NSDataWritingAtomic error:&error];
if (!success) {
NSLog(@"Failed to write file: %@", error.localizedDescription);
return NO;
}
NSLog(@"Image saved successfully: %@", filePath);
return YES;
}
@end异常处理
1. 捕获和处理异常
objc
@interface ExceptionHandler : NSObject
+ (void)safeExecute:(void(^)(void))block operation:(NSString *)operation;
@end
@implementation ExceptionHandler
+ (void)safeExecute:(void(^)(void))block operation:(NSString *)operation {
@try {
if (block != nil) {
block();
}
} @catch (NSInvalidArgumentException *exception) {
NSLog(@"%@ failed: Invalid argument - %@", operation, exception.reason);
} @catch (NSException *exception) {
NSLog(@"%@ failed: Unexpected exception - %@", operation, exception.reason);
}
}
@end2. 重试机制
objc
@interface RetryHandler : NSObject
@property (nonatomic, strong) FBBeautyEffectEngine *engine;
@end
@implementation RetryHandler
static const int MAX_RETRY = 3;
static const NSTimeInterval RETRY_DELAY = 0.1;
- (FBImageFrame *)processImageWithRetry:(FBImageFrame *)input {
for (int i = 0; i < MAX_RETRY; i++) {
@try {
FBImageFrame *result = [self.engine processImage:input processMode:FBProcessModeVideo];
if (result != nil) {
return result;
}
} @catch (NSException *exception) {
NSLog(@"Attempt %d failed: %@", i + 1, exception.reason);
}
if (i < MAX_RETRY - 1) {
[NSThread sleepForTimeInterval:RETRY_DELAY];
}
}
NSLog(@"All retry attempts failed");
return nil;
}
@endmacOS 特有错误处理
1. 沙盒权限处理
objc
@interface SandboxPermissionHandler : NSObject
+ (BOOL)requestFileAccessPermission:(NSURL *)fileURL;
+ (BOOL)hasFileAccessPermission:(NSURL *)fileURL;
@end
@implementation SandboxPermissionHandler
+ (BOOL)requestFileAccessPermission:(NSURL *)fileURL {
// macOS 沙盒环境下需要请求文件访问权限
NSError *error = nil;
BOOL success = [fileURL startAccessingSecurityScopedResource];
if (!success) {
NSLog(@"Failed to request file access permission: %@", error.localizedDescription);
}
return success;
}
+ (BOOL)hasFileAccessPermission:(NSURL *)fileURL {
// 检查是否有文件访问权限
NSFileManager *fileManager = [NSFileManager defaultManager];
return [fileManager isReadableFileAtPath:fileURL.path];
}
@end2. 多显示器环境错误处理
objc
@interface MultiDisplayErrorHandler : NSObject
+ (void)handleDisplayChange:(NSNotification *)notification;
+ (BOOL)validateDisplayConfiguration;
@end
@implementation MultiDisplayErrorHandler
+ (void)handleDisplayChange:(NSNotification *)notification {
// 处理显示器配置变化
NSArray *screens = [NSScreen screens];
for (NSScreen *screen in screens) {
CGFloat scaleFactor = screen.backingScaleFactor;
if (scaleFactor > 1.0) {
// Retina 显示器
NSLog(@"Retina display detected with scale factor: %.1f", scaleFactor);
}
}
// 重新验证配置
if (![self validateDisplayConfiguration]) {
NSLog(@"Display configuration validation failed");
}
}
+ (BOOL)validateDisplayConfiguration {
NSArray *screens = [NSScreen screens];
if (screens.count == 0) {
NSLog(@"No displays detected");
return NO;
}
// 验证所有显示器配置
for (NSScreen *screen in screens) {
if (screen.frame.size.width <= 0 || screen.frame.size.height <= 0) {
NSLog(@"Invalid screen dimensions");
return NO;
}
}
return YES;
}
@end调试技巧
1. 错误信息收集
objc
@interface DebugInfoCollector : NSObject
+ (NSString *)collectErrorInfo:(int)errorCode operation:(NSString *)operation exception:(NSException *)exception;
@end
@implementation DebugInfoCollector
+ (NSString *)collectErrorInfo:(int)errorCode operation:(NSString *)operation exception:(NSException *)exception {
NSMutableString *info = [NSMutableString string];
[info appendFormat:@"Operation: %@\n", operation];
[info appendFormat:@"Error Code: %d\n", errorCode];
[info appendFormat:@"Timestamp: %lld\n", (long long)([[NSDate date] timeIntervalSince1970] * 1000)];
if (exception != nil) {
[info appendFormat:@"Exception: %@\n", exception.name];
[info appendFormat:@"Reason: %@\n", exception.reason];
}
// 添加系统信息
[info appendString:@"System Info:\n"];
NSProcessInfo *processInfo = [NSProcessInfo processInfo];
[info appendFormat:@"Processor Count: %lu\n", (unsigned long)processInfo.processorCount];
[info appendFormat:@"Active Processor Count: %lu\n", (unsigned long)processInfo.activeProcessorCount];
return [info copy];
}
@end2. 性能监控
objc
@interface PerformanceMonitor : NSObject
@property (nonatomic, assign) NSTimeInterval startTime;
@property (nonatomic, assign) NSInteger errorCount;
@end
@implementation PerformanceMonitor
- (void)startOperation {
self.startTime = [[NSDate date] timeIntervalSince1970];
}
- (void)endOperation:(NSString *)operation success:(BOOL)success {
NSTimeInterval duration = [[NSDate date] timeIntervalSince1970] - self.startTime;
if (!success) {
self.errorCount++;
NSLog(@"%@ failed after %.2fms (Error count: %ld)",
operation, duration * 1000, (long)self.errorCount);
} else if (duration > 0.05) {
// macOS 性能更好,阈值可以设置得更低
NSLog(@"%@ took %.2fms (slow operation)", operation, duration * 1000);
}
}
@end总结
遵循这些错误处理最佳实践可以帮助你:
- 提高应用稳定性: 通过检查 API 返回值和异常处理
- 改善用户体验: 通过友好的错误提示和恢复机制
- 便于问题排查: 通过详细的日志记录和错误信息收集
- 优化性能: 通过合理的错误恢复策略和资源管理
- macOS 优化: 通过沙盒权限处理和多显示器环境支持
记住要根据实际 SDK 的错误码定义调整错误处理逻辑,并持续监控和改进错误处理机制。macOS 平台相比 iOS 有更大的内存和更强的处理能力,但也要注意沙盒权限和多显示器环境的特殊处理。