可可 – 处理陈旧的NSURL书签的正确方法是什么?

当从安全范围的书签解析NSURL时,如果用户重命名或移动了该文件或文件夹,书签将会失效。苹果公司的文件说明了这一点:

isStale

On return, if YES, the bookmark data is stale. Your app should
create a new bookmark using the returned URL and use it in place of
any stored copies of the existing bookmark.

不幸的是,这很少适用于我。它可能在5%的时间工作。尝试使用返回的URL创建新书签会导致错误,代码256,并在控制台中查找来自sandboxd的消息,表示拒绝更新的URL上的文件读取数据。

注意如果重新生成书签功能,它似乎仅在第一次重新生成时才起作用。如果文件夹/文件再次被移动/重命名,似乎永远不会工作。

我最初创建&存储书签

-(IBAction)bookmarkFolder:(id)sender {
  _openPanel = [NSOpenPanel openPanel];
  _openPanel.canChooseFiles = NO;
  _openPanel.canChooseDirectories = YES;
  _openPanel.canCreateDirectories = YES;
  [_openPanel beginSheetModalForWindow:self.window completionHandler:^(NSInteger result) {
    if (_openPanel.URL != nil) {
      NSError *error;
      NSData *bookmark = [_openPanel.URL bookmarkDataWithOptions:NSURLBookmarkCreationWithSecurityScope
                                  includingResourceValuesForKeys:nil
                                                   relativeToURL:nil
                                                           error:&error];
      if (error != nil) {
        NSLog(@"Error bookmarking selected URL: %@", error);
        return;
      }
      NSUserDefaults *userDefaults = [NSUserDefaults standardUserDefaults];
      [userDefaults setObject:bookmark forKey:@"bookmark"];
    }
  }];
}

用于解析书签的代码

-(void)resolveStoredBookmark {
  NSUserDefaults *userDefaults = [NSUserDefaults standardUserDefaults];
  NSData *bookmark = [userDefaults objectForKey:@"bookmark"];
  if (bookmark == nil) {
    NSLog(@"No bookmark stored");
    return;
  }
  BOOL isStale;
  NSError *error;
  NSURL *url = [NSURL URLByResolvingBookmarkData:bookmark
                                         options:NSURLBookmarkResolutionWithSecurityScope
                                   relativeToURL:nil
                             bookmarkDataIsStale:&isStale
                                           error:&error];
  if (error != nil) {
    NSLog(@"Error resolving URL from bookmark: %@", error);
    return;
  } else if (isStale) {
    if ([url startAccessingSecurityScopedResource]) {
      NSLog(@"Attempting to renew bookmark for %@", url);
      // NOTE: This is the bit that fails, a 256 error is 
      //       returned due to a deny file-read-data from sandboxd
      bookmark = [url bookmarkDataWithOptions:NSURLBookmarkCreationWithSecurityScope
               includingResourceValuesForKeys:nil
                                relativeToURL:nil
                                        error:&error];
      [url stopAccessingSecurityScopedResource];
      if (error != nil) {
        NSLog(@"Failed to renew bookmark: %@", error);
        return;
      }
      [userDefaults setObject:bookmark forKey:@"bookmark"];
      NSLog(@"Bookmark renewed, yay.");
    } else {
      NSLog(@"Could not start using the bookmarked url");
    }
  } else {
    NSLog(@"Bookmarked url resolved successfully!");
    [url startAccessingSecurityScopedResource];
    NSArray *contents = [NSFileManager.new contentsOfDirectoryAtPath:url.path error:&error];
    [url stopAccessingSecurityScopedResource];
    if (error != nil) {
      NSLog(@"Error reading contents of bookmarked folder: %@", error);
      return;
    }
    NSLog(@"Contents of bookmarked folder: %@", contents);
  }
}

当书签过时时,生成的已解析的URL确实指向正确的位置,尽管[url startAccessingSecurityScopedResource]返回YES,但实际上我无法访问该文件。

也许我误解了关于陈旧书签的文档,但我希望我只是做一些愚蠢的事情。每次将书签文件/文件夹重命名或移动时,弹出一个NSOpenPanel,此时我唯一的其他选项似乎是可笑的。

我应该补充说,我有com.apple.security.files.bookmarks.app-scope,com.apple.security.files.user-selected.read-write和com.apple.security.app-sandbox都设置为true在我的权利文件。

经过很多令人失望的测试,我得出以下结论。尽管如此,它们令人失望,因为用户的经验远非理想,对于开发人员而言,由于愿意去帮助用户重新建立对书签资源的引用,所以对开发人员来说是一个很大的痛苦。

当我在下面说“续订”时,我的意思是“生成一个新的书签,以使用从陈旧书签解析的URL替换陈旧的书签。”

>只要书签资源在您的应用程序已具有访问权限的目录中移动或重命名,则续订将始终起作用。因此,默认情况下,它始终可以在应用程序的容器文件夹中运行。
>如果将书签资源移入应用程序没有权限访问的文件夹,则更新失败。例如用户将容器文件夹中的文件夹拖动到容器文件夹外的某个文件夹。您将能够解析URL,但不能访问或更新书签。
>如果书签资源位于应用程序无权访问的文件夹中,然后重命名,则更新失败。这意味着用户可以明确地授予应用程序对资源的访问权限,然后通过重新命名来无意中撤销该访问权限。
>如果资源被移动到另一个卷,解决方案将失败。不知道这是一般书签的限制,还是在沙盒应用程序中使用时的限制。

对于问题2& 3,由于书签网址的解析功能正常,您处于开发人员的体面位置。告诉他们他们需要哪些资源来授予您的应用访问权限以及它们的位置,至少可以引导用户。通过让他们选择一个包含(直接或间接)所有需要更新书签的资源的文件夹,可以改进体验。这甚至可以是音量,如果他们愿意为您的应用程序提供更多的访问权限,则可以完全解决问题。

对于问题4,解决方案根本不起作用。由于您无法解析新的位置,用户将无需任何提示来重新定位文件。在我目前的应用程序中做的一件事,减少了这个问题的痛苦是为了存储一个书签的任何资源添加一个扩展属性。至少这样做可以让用户选择一个文件夹来搜索以前关联的资源。

令人沮丧的限制,但书签仍然胜过存储静态路径。

http://stackoverflow.com/questions/23954662/what-is-the-correct-way-to-handle-stale-nsurl-bookmarks

本站文章除注明转载外,均为本站原创或编译
转载请明显位置注明出处:可可 – 处理陈旧的NSURL书签的正确方法是什么?