Sandboxed Mac应用程序耗尽了安全范围的URL资源

dan*_*elv 13 macos cocoa sandbox objective-c

我正在开发一个Mac应用程序,它使用NSOpenPanel提示用户输入文件.应用程序是沙箱(在OSX 10.9.4上测试).我注意到如果我打开大量文件(~3000),打开的面板会开始向日志发出错误.如果我尝试在chucks中打开少量文件多次,也会发生这种情况.

在第一次出现错误之后,每次再次使用NSOpenPanel打开文件时,无论文件数量多少,都会再次生成这些错误(直到应用程序关闭).

错误消息如下所示:

TestPanel[98508:303] __41+[NSSavePanel _consumeSandboxExtensions:]_block_invoke: sandbox_consume_fs_extension failed
Run Code Online (Sandbox Code Playgroud)

我试图打开的每个文件一行.

我设法用一个简单的应用程序重现这种行为:一个带有单个按钮的沙盒应用程序调用以下代码:

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]);
}];
Run Code Online (Sandbox Code Playgroud)

错误出现在代码到达完成处理程序之前.

似乎我仍然可以从完成处理程序中的面板中获取URL,但它确实污染了系统日志.

编辑:

似乎此问题与NSOpenPanel/NSSavePanel面板没有直接关系.使用drap/drop with files时会发生非常类似的事情.像这样的东西:

- (NSDragOperation)draggingEntered:(id <NSDraggingInfo>)sender {
    ...
    NSPasteboard *pboard = [sender draggingPasteboard];
    if ([[pboard types] containsObject:NSURLPboardType]) {
        NSArray *urls = [pboard readObjectsForClasses:@[[NSURL class]] options:nil];
    }
    ...
}
Run Code Online (Sandbox Code Playgroud)

拖动大量文件时会生成以下日志消息("魔术"数字似乎在2900左右):

Consume sandbox extension for itemIdentifier (2937) from pasteboard failed!
Run Code Online (Sandbox Code Playgroud)

与NSOpenPanel一样,在第一次出现之后,每个丢弃的文件都会在日志中生成相同的错误.

编辑2:

@mahal tertin的回复向我指出了正确的方向.问题确实存在于文件数量和安全范围URL资源有限的事实上.

但是,似乎找不到合理的解决方案.问题是,当用户在NSOpenPanel上单击"确定"(或删除拖放感知控件上的文件)时,操作系统已经尝试创建这些安全范围的URL并隐式调用startAccessingSecurityScopedResource您.因此,如果用户尝试打开的文件超过限制,则资源将耗尽,唯一的选择是关闭并重新启动应用程序.

调用stopAccessingSecurityScopedResource返回的URL似乎可以释放资源,但Apple 官方开发者论坛上的代表不鼓励这种解决方案(链接在登录后面).

似乎该应用程序受用户的摆布,不打开太多文件.这甚至不是立刻,因为没有批准的方式来释放这些资源.您可以在文档中警告用户,甚至可以通过应用程序内警告警告用户,但是无法防止他们弄乱应用程序并强制重新启动.

因此,如果应用程序运行时间足够长并且用户不断打开文件,则应用程序最终将无法使用.

仍在寻找合理的解决方案.

dan*_*elv 8

在高低搜索并在各个地方询问之后,我将结束这个问题并得出结论,没有答案或解决方案.我发布有关此信息的已知信息以供将来参考.

建议的所有解决方案只是可以最小化问题的解决方法,并尝试引导用户不要尝试打开太多文件.但实际上没有任何办法可以解决这个问题.

以下是有关此问题的已知事实:

  • 无论你做什么,用户都可以尝试在NSOpenPanel对话框中打开太多文件并耗尽安全范围的URL资源
  • 一旦这些资源耗尽,就无法再打开任何文件进行读/写.应用程序需要关闭并重新打开
  • 即使用户没有尝试一次打开太多文件,如果应用程序运行时间足够长并且用户随时间打开足够多的文件,应用程序仍可能耗尽这些资源,因为startAccessingSecurityScopedResource对于使用NSOpenPanel 打开的文件会自动调用(或者拖动/什么都没有关闭这些资源
  • 调用stopAccessingSecurityScopedResource开放面板检索到的所有URL将释放这些资源,但Apple不鼓励这种做法,称它可能与未来的解决方案不兼容
  • 当您收到NSOpenPanel(或拖/放)URL列表,也没有办法知道是否所有的URL进行成功访问,或者如果有网址是超过限额,因此是无效的.
  • Apple意识到这一点,并可能在将来修复它.它仍然没有在10.10中修复,当然,这对当前/以前的OSX版本上运行的当前应用程序没有帮助.

苹果似乎真的放弃了这个,沙盒实施似乎非常草率和短视.

  • 不,我没有提交雷达.我停止归档雷达因为我开始觉得这是浪费我的时间.这些雷达大多被忽略,没有反馈,没有确认,没有搜索其他雷达的能力.如果Apple希望我为他们做肮脏的工作,查找,调试,复制和报告错误,他们最好给我适当的工具和反馈.苹果的"你提出了一个雷达,也许是第1000次,然后也许我们会调查它,也许不是"态度开始让我紧张.抱歉. (4认同)

mah*_*tin 6

您遇到的行为是因为安全范围资源有限:

NSURL - (BOOL)startAccessingSecurityScopedResource告诉

如果泄漏了足够的内核资源,您的应用程序将无法将文件系统位置添加到其沙箱中...

目前的限制大致与您的经历相同.请参阅: 安全范围书签的当前内核资源限制是什么?

为了防止它:

  • 只在特定时间开始访问您需要的SSB,然后停止访问它们
  • 开始访问不是文件而是封闭文件夹:要求用户不要选择文件而是选择完整文件夹.这将授予您访问该目录下的整个树的权限
  • on draggingEntered:显示带有封闭目录的NSOpenPanel以授予访问权限

  • 谢谢回复.这指向了正确的方向.但是,我没有明确地调用startAccessingSecurityScopedResource.我假设在打开/删除文件时,NSSavePanel/drag会隐式调用它们.因此,当我开始使用这些资源时,当我获得URL列表(从面板或拖动)时,这已经太晚了,资源已经用尽了.使用文件夹而不是文件不适用于我的应用程序,因为我需要用户能够选择单个文件.我也看不到你回答的第3点是如何解决问题的. (2认同)