Mac保存对话框覆盖文件时触发sandbox扩展失败异常如何解决?
NSSavePanel覆盖保存触发sandbox异常解决方案
问题复现条件
- 首次使用任意名称保存文件,例如
test1 - 再次打开保存对话框,默认推荐文件名仍为
test1 - 点击「保存」后选择「替换」覆盖已有文件,直接触发异常
例外情况:执行替换操作前,手动点击对话框内访达窗口中的
test1文件,不会触发异常
相关代码与报错
问题触发代码:
#define kMaxPathLength 1023 [self setDialogResult:[dialog runModal]]; if ([self dialogResult] == NSOKButton) { char pathBuffer[kMaxPathLength]; @try{ // 下行为异常触发点 NSString* pathcopy = [[dialog URL] path]; [pathcopy getCString:pathBuffer maxLength:kMaxPathLength encoding: NSUTF8StringEncoding]; } @catch(NSException* e){ // 断点位置 } }
合并写法也会触发相同异常:
[[[dialog URL] path] getCString:pathBuffer maxLength:kMaxPathLength encoding:NSUTF8StringEncoding];
异常日志:
ROSP: sandbox extension failure: nil result or wrong class type ((null)) for finalURL
问题出现环境:Xcode 12、macOS Catalina系统。
解决方案
该问题是Catalina系统NSSavePanel的已知权限bug,覆盖保存时系统未正确为应用授予目标文件的访问权限,导致[dialog URL]返回nil触发异常,可通过以下任意方案解决:
- 使用filename属性替代URL获取路径
NSSavePanel的filename是兼容旧版本的API,不受该sandbox bug影响:
// 替换原来的[[dialog URL] path]即可 NSString *pathcopy = dialog.filename;
- 开启canCreateDirectories属性
初始化保存面板时添加该配置,强制系统保存时重新校验文件权限:
dialog.canCreateDirectories = YES;
- 增加nil判断与降级逻辑
如果需要兼容多种场景,可增加URL校验逻辑,异常时降级使用filename获取路径:
@try{ NSURL *fileURL = [dialog URL]; NSString *pathcopy = nil; if (fileURL) { pathcopy = [fileURL path]; } else { pathcopy = dialog.filename; } [pathcopy getCString:pathBuffer maxLength:kMaxPathLength encoding: NSUTF8StringEncoding]; } @catch(NSException* e){ // 自定义异常处理逻辑 }
- 升级系统适配版本
该bug在macOS Big Sur(11.0)及以上版本已被官方修复,如果应用最低支持版本可升级到11.0,直接升级即可消除问题。
内容的提问来源于stack exchange,提问作者gil_mo
相关产品推荐
相关产品推荐

