【发布时间】:2014-09-02 15:59:04
【问题描述】:
我正在开发一个使用 NSOpenPanel 提示用户输入文件的 Mac 应用程序。该应用程序是沙盒的(在 OSX 10.9.4 上测试)。我注意到如果我打开大量文件(~3000),打开的面板开始向日志发出错误。如果我多次尝试在卡盘中打开较少数量的文件,也会发生这种情况。
在第一次开始出现错误后,每次再次使用 NSOpenPanel 打开文件,无论文件多少,都会再次产生这些错误(直到应用程序关闭)。
错误信息如下所示:
TestPanel[98508:303] __41+[NSSavePanel _consumeSandboxExtensions:]_block_invoke: sandbox_consume_fs_extension failed
我尝试打开的每个文件对应一行。
我设法用一个简单的应用程序重现了这种行为:一个带有单个按钮的沙盒应用程序,调用以下代码:
NSOpenPanel* panel = [NSOpenPanel openPanel];
[panel setAllowsMultipleSelection:YES];
[panel setCanChooseDirectories:NO];
[panel setCanChooseFiles:YES];
[panel beginSheetModalForWindow:[self window] completionHandler:^(NSInteger result) {
NSLog(@"%lu", [panel.URLs count]);
}];
错误出现在代码到达完成处理程序之前。
似乎我仍然可以从完成处理程序的面板中获取 URL,但它确实污染了系统日志。
编辑:
似乎这个问题与 NSOpenPanel/NSSavePanel 面板没有直接关系。对文件使用拖放/拖放时会发生非常相似的事情。像这样的:
- (NSDragOperation)draggingEntered:(id <NSDraggingInfo>)sender {
...
NSPasteboard *pboard = [sender draggingPasteboard];
if ([[pboard types] containsObject:NSURLPboardType]) {
NSArray *urls = [pboard readObjectsForClasses:@[[NSURL class]] options:nil];
}
...
}
这将在拖动大量文件时生成以下日志消息(“神奇”数字似乎在 2900 左右):
Consume sandbox extension for itemIdentifier (2937) from pasteboard failed!
与 NSOpenPanel 一样,在第一次发生这种情况后,删除的每个文件都会在日志中生成相同的错误。
编辑 2:
@mahal tertin 的回复为我指明了正确的方向。问题确实在于文件的数量以及安全范围的 URL 资源是有限的。
但是,似乎没有找到合理的解决方案。问题在于,当用户在 NSOpenPanel 上单击“确定”(或将文件放在拖放感知控件上)时,操作系统已经在后台尝试创建这些安全范围的 URL 并为您隐式调用 startAccessingSecurityScopedResource。因此,如果用户尝试打开的文件超过限制,资源就会耗尽,唯一的选择就是关闭并重新启动应用程序。
在返回的 URL 上调用 stopAccessingSecurityScopedResource 似乎可以释放资源,但 Apple 代表在 official developers forums 上不鼓励这种解决方案(链接在登录后面)。
似乎该应用程序受制于用户不要打开太多文件。这甚至不是一次,因为没有批准的方式来释放这些资源。您可以在文档中甚至使用应用内警报来警告用户,但没有办法阻止他们弄乱应用并强制重启。
因此,如果应用运行时间足够长并且用户不断打开文件,应用最终将无法使用。
仍在为此寻找合理的解决方案。
【问题讨论】:
标签: objective-c macos cocoa sandbox