objective-c - NSDocumentController 最近的文档沙盒(奇怪)问题

标签 objective-c macos nsdocumentcontroller recent-documents

我使用的是 Objective-C、Xcode 11、macOS 而不是 iOS、沙盒应用程序。

我需要手动更新最近的文档菜单。 我将 URL 存储在书签中,以便我可以根据沙箱访问它们。

奇怪的是代码 A 可以工作,但 B 却不能。 有人对此有解释吗?

// Code A
NSURL* bookmarkURL = (some valid URL from bookmark);
[bookmarkURL startAccessingSecurityScopedResource]; <- returns TRUE
[[NSDocumentController sharedDocumentController] noteNewRecentDocumentURL:bookmarkURL];
//[bookmarkURL stopAccessingSecurityScopedResource]; <-- Without closing access it works

// Code B
NSURL* bookmarkURL = (some valid URL from bookmark);
[bookmarkURL startAccessingSecurityScopedResource]; <- returns TRUE
[[NSDocumentController sharedDocumentController] noteNewRecentDocumentURL:bookmarkURL];
[bookmarkURL stopAccessingSecurityScopedResource];

B 不起作用(关闭安全访问)!不关闭安全访问感觉是错误的。 对于情况 B,会引发以下错误

Insert failed for list identifier com.apple.LSSharedFileList.ApplicationRecentDocuments Error: Error Domain=NSPOSIXErrorDomain Code=1 "Operation not permitted" (Restricted by sandbox) UserInfo={NSDebugDescription=Restricted by sandbox}

如果不启动安全访问,就会抛出相同的错误(显然)。

最佳答案

看来,只要文档位于(手动管理的)最近列表中,应用程序就应该保留安全范围的权限。

就我而言,错误表现在

  • “文件/打开最近的文件”中的“清除菜单”菜单项保持灰色
  • 最近的列表在应用启动后并未持续存在
  • 最近的列表未出现在 Dock 上。
  • 我在 Console.app 中遇到错误:

    Insert failed for list identifier com.apple.LSSharedFileList.ApplicationRecentDocuments Error: Error Domain=NSPOSIXErrorDomain Code=1 "Operation not permitted" (Access to list denied) UserInfo={NSDebugDescription=Access to list denied}

似乎最近的文档列表在内部是由一个单独的线程管理的,该线程又与系统进程sharedfilelistd进行通信。如果我 stopAccessingSecurityScopedResource,我可以通过以下调用堆栈(缩写)在 Console.app 中观察到 sandboxd 违规:

Sandbox: MyApp(24093) deny(1) file-read-data /path/to/recent/document

Thread 1 (id: 364320):
0   libsystem_kernel.dylib          0x00007ff81b2265b2 mach_msg2_trap + 10
1   libsystem_kernel.dylib          0x00007ff81b22d5e4 mach_msg_overwrite + 692
2   libsystem_kernel.dylib          0x00007ff81b22689a mach_msg + 19
3   libdispatch.dylib               0x00007ff81b0dce6f _dispatch_mach_send_and_wait_for_reply + 518
4   libdispatch.dylib               0x00007ff81b0dd273 dispatch_mach_send_with_result_and_wait_for_reply + 50
5   libxpc.dylib                    0x00007ff81afacb97 xpc_connection_send_message_with_reply_sync + 238
6   Foundation                      0x00007ff81c18b423 __NSXPCCONNECTION_IS_WAITING_FOR_A_SYNCHRONOUS_REPLY__ + 9
7   Foundation                      0x00007ff81c1893c1 -[NSXPCConnection _sendInvocation:orArguments:count:methodSignature:selector:withProxy:] + 3215
8   Foundation                      0x00007ff81c188723 -[NSXPCConnection _sendInvocation:withProxy:] + 91
9   CoreFoundation                  0x00007ff81b3234c6 ___forwarding___ + 671
10  CoreFoundation                  0x00007ff81b323198 _CF_forwarding_prep_0 + 120
11  SharedFileList                  0x00007ff823244145 __44-[SFLGenericList _insertItem:atIndex:error:]_block_invoke + 695
12  libsystem_trace.dylib           0x00007ff81afeaa0e _os_activity_initiate_impl + 51
13  SharedFileList                  0x00007ff823243ddc -[SFLGenericList _insertItem:atIndex:error:] + 301
14  SharedFileList                  0x00007ff823243ba5 __46-[SFLGenericList _insertItem:afterItem:error:]_block_invoke + 378
15  libsystem_trace.dylib           0x00007ff81afeaa0e _os_activity_initiate_impl + 51
16  SharedFileList                  0x00007ff823243961 -[SFLGenericList _insertItem:afterItem:error:] + 316
17  SharedFileList                  0x00007ff8232433b2 -[SFLGenericList insertItem:afterItem:error:] + 100
18  SharedFileList                  0x00007ff82323c085 +[SFLList(LSSharedFileListSupport) itemByInsertingAfterItem:name:URL:propertiesToSet:propertiesToClear:list:] + 1370
19  SharedFileList                  0x00007ff82323f3f7 LSSharedFileListInsertItemURL + 183
20  AppKit                          0x00007ff81e80868f -[_NSRecentItemsMenuController _notePendingRecentDocumentURLsForKey:documentsSnapshot:] + 677
21  Foundation                      0x00007ff81c1ada71 __NSBLOCKOPERATION_IS_CALLING_OUT_TO_A_BLOCK__ + 7
22  Foundation                      0x00007ff81c1ad969 -[NSBlockOperation main] + 98
23  Foundation                      0x00007ff81c1ad902 __NSOPERATION_IS_INVOKING_MAIN__ + 17
24  Foundation                      0x00007ff81c1acc02 -[NSOperation start] + 782
25  Foundation                      0x00007ff81c1ac8e8 __NSOPERATIONQUEUE_IS_STARTING_AN_OPERATION__ + 17
26  Foundation                      0x00007ff81c1ac7b6 __NSOQSchedule_f + 182
27  libdispatch.dylib               0x00007ff81b0d1771 _dispatch_block_async_invoke2 + 83
...

这表明系统启动了一个线程,执行一些名为 [_NSRecentItemsMenuController _notePendingRecentDocumentURLs...] 的异步分派(dispatch)操作,该操作又向 SFL(共享文件列表)发出 XPC 调用),这会以某种方式导致尝试读取指定文档,该文档被应用程序沙箱阻止。

因此我们可以得出结论,在调用 noteNewRecentDocumentURL 后,应用程序仍然必须持有访问该文件的权限,因为最近列表的实际管理是异步发生在另一个线程上的,并且该线程必须能够检查文件是否存在或出于其他原因读取文件。

我重写了我的应用程序,以便只要关联的文件位于最近的列表中,它就保留安全范围的资源,并在它们从列表中删除时停止访问它们。互联网智慧称有几千个此类资源可用,请参阅What are the current kernel resource limits on security-scoped bookmarks? 。由于我最近的列表永远不会增长到这样的大小,因此我的应用程序永远不会耗尽内核资源。

另请参阅https://developer.apple.com/forums/thread/710278

关于objective-c - NSDocumentController 最近的文档沙盒(奇怪)问题,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/59442880/

相关文章:

objective-c - 弹出时 UIViewController 未被释放

objective-c - Xcode Cocoa Objective C 使用 NSTask 执行 "Find"Shell 命令返回语法

ios - 如何减少 reloadData 的故障(视觉上)?

objective-c - OS X 版本的 bringSubviewToFront :?

ios - 如何在 OS X 中以编程方式借助文件路径打开文件夹或文件?

ios - 垂直自动布局 subview

macos - 你如何在 mac preview 10.7 中重新加载文件?

swift - 实时绘图哪种方式更好?

cocoa NSDocument : getting autosave to work

objective-c - 对 `[[NSDocumentController sharedDocumentController] recentDocumentURLs]` 的调用挂起