macOS Objective-C:重启后重新加载用户选择的NSImage问题
macOS沙盒下安全范围书签恢复图片加载的正确方案
你的代码存在两个核心问题,导致无法正常加载图片:
- 路径格式错误:
url.absoluteString返回的是带file://前缀的URL字符串,而NSImage initWithContentsOfFile:需要的是本地文件路径(不带协议前缀),应该使用url.path。 - 未启动安全范围资源访问:沙盒下使用安全范围书签解析出URL后,必须调用
startAccessingSecurityScopedResource获取临时访问权限,否则无法读取文件;访问完成后要调用stopAccessingSecurityScopedResource释放权限。
修正后的AwakeFromNib加载代码
NSData *bookmark = [preferences objectForKey:@"bookmark"]; if (!bookmark) { return; // 无书签数据直接返回 } NSError *error = nil; BOOL isStale; NSURL *url = [NSURL URLByResolvingBookmarkData:bookmark options:NSURLBookmarkResolutionWithSecurityScope relativeToURL:nil bookmarkDataIsStale:&isStale error:&error]; if (error) { NSLog(@"解析书签失败:%@", error); return; } // 检查书签是否过期,过期则需要重新获取用户授权并创建新书签 if (isStale) { NSLog(@"书签已过期,请重新选择图片"); // 这里可触发重新选择图片的逻辑,重新生成书签 return; } // 启动安全范围资源访问 if ([url startAccessingSecurityScopedResource]) { NSString *path = url.path; // 使用正确的本地路径 NSImage *imgC = [[NSImage alloc] initWithContentsOfFile:path]; imageView2.image = imgC; // 完成访问后停止权限 [url stopAccessingSecurityScopedResource]; } else { NSLog(@"无法获取安全范围资源访问权限"); }
书签创建代码的优化建议
你的创建代码基本正确,但建议添加userDefaults同步操作,确保书签数据立即写入磁盘:
NSData *bookmark = nil; NSError *error = nil; bookmark = [url bookmarkDataWithOptions:NSURLBookmarkCreationWithSecurityScope includingResourceValuesForKeys:nil relativeToURL:nil error:&error]; if (error) { NSLog(@"创建书签失败:%@", error); [NSApp presentError:error]; return; } NSUserDefaults *userDefaults = [NSUserDefaults standardUserDefaults]; [userDefaults setObject:bookmark forKey:@"bookmark"]; [userDefaults synchronize]; // 确保数据立即写入磁盘
额外注意事项
- 确保你的App已开启沙盒的用户选定文件权限(在Xcode的项目设置>Signing & Capabilities>App Sandbox>File Access中勾选)。
- 如果书签过期(
isStale为YES),需要引导用户重新选择图片并生成新书签,因为旧书签已经失效。
内容的提问来源于stack exchange,提问作者GeraldTheGerm
相关产品推荐
相关产品推荐

