处理陈旧的NSURL书签的正确方法是什么? [英] What is the correct way to handle stale NSURL bookmarks?

查看:358
本文介绍了处理陈旧的NSURL书签的正确方法是什么?的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

当从安全范围的书签解析NSURL时,如果用户已重命名或移动了该文件或文件夹,则该书签将失效。 Apple的文档说明了关于陈旧性:

When resolving an NSURL from a security scoped bookmark, if the user has renamed or moved that file or folder, the bookmark will be stale. Apple's document says this regarding staleness:


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%的时间工作。尝试使用返回的网址创建新书签会导致错误,代码为256,并在控制台中查看来自沙箱的消息表示拒绝更新后的网址上的文件读取数据。

Unfortunately, this rarely works for me. It may work 5% of the time. Attempting to create a new bookmark using the returned URL results in an error, code 256, and looking in Console reveals a message from sandboxd saying deny file-read-data on the updated URL.

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

Note If regenerating the bookmark does work, it seems to only work the first time it is regenerated. It seems to never work should the folder/file be moved/renamed again.

我最初创建&存储书签

-(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"];
    }
  }];
}

解析书签的代码

Code that resolves the 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 startAccessingSecurityScopedResource]返回是。

When the bookmark is stale, the resulting resolved URL does point to the correct location, I just can't actually access the file despite the fact that [url startAccessingSecurityScopedResource] returns YES.

也许我错误的解释有关stale书签,但我希望我只是做一些蠢事。每次重命名或移动一个带书签的文件/文件夹时,弹出一个NSOpenPanel,我现在的唯一其他选项看起来很可笑。

Perhaps I'm misinterpreting the documentation regarding stale bookmarks, but I'm hoping I'm just doing something stupid. Popping an NSOpenPanel each time a bookmarked file/folder is renamed or moved, my only other option at this point, seems ridiculous.

com.apple.security.files.bookmarks.app-scope , com.apple.security.files.user-selected.read-write com.apple.security

I should add that I have com.apple.security.files.bookmarks.app-scope, com.apple.security.files.user-selected.read-write, and com.apple.security.app-sandbox all set to true in my entitlements file.

推荐答案

在我的授权文件中设置为true。得出以下结论。虽然逻辑,他们是令人失望的,因为由此产生的用户体验远不是理想的,并为开发人员,根据他们愿意去帮助用户重新建立对书签资源的引用多少痛苦。

After a lot of disappointing testing I've come to the following conclusions. Though logical, they're disappointing since the resulting experience for users is far from ideal and a significant pain for developers depending on how far they're willing to go to help users re-establish references to bookmarked resources.

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

When I say "renew" below, I mean "generate a new bookmark to replace a stale bookmark using the URL resolved from the stale bookmark."


  1. 续订只要在您的应用程式已有权限存取的目录中移动或重新命名已加入书签的资源,就会一直有效。

  1. Renewal always works as long as the bookmarked resource is moved or renamed within a directory that your app already has permission to access. So, by default, it always works inside your application's container folder.

如果将添加书签的资源移动到您的应用程序没有权限的文件夹中,则续订将失败访问。例如用户将文件夹从容器文件夹拖动到容器文件夹外的某个文件夹。

Renewal fails if a bookmarked resource is moved into a folder your application does not have permission to access. e.g. User drags a folder from your container folder to some folder outside the container folder. You will be able to resolve the URL, but not access nor renew the bookmark.

如果书签资源位于您应用程式所没有的资料夹中,续约就会失败有访问权限,然后重命名。

Renewal fails if a bookmarked resource lives in a folder your application doesn't have access to and is then renamed. This means a user can explicitly grant your application access to a resource, then inadvertently revoke that access just by renaming it.

如果资源移动到某个资源,则解析将失败另一卷。

Resolution fails if a resource is moved to another volume. Not sure if this is a limitation of bookmarks in general or just when used in a sandboxed application.

对于问题2,您不能确定这是一个限制书签还是在沙箱应用程序中使用的限制。 & 3你作为开发商在一个体面的位置,因为书签的URL的解析工作。您可以至少通过告诉用户他们需要哪些资源来授予您的应用访问权限以及访问权限。通过让他们选择包含(直接或间接)您需要更新书签的所有资源的文件夹,可以改善体验。这甚至可以是卷,如果他们愿意给你的应用程序这么多访问,完全解决问题。

For issues 2 & 3 you're in a decent position as the developer since resolution of the bookmarked URL does work. You can at least lead the user by telling them exactly which resources they need to grant your app access to and where they are. The experience could be improved by having them select a folder that contains (directly or indirectly) all resources that you need to renew a bookmark for. This could even be the volume, which solves the problem completely if they're willing to give your application this much access.

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

For issue 4, resolution doesn't work at all. The user will have to relocate the file without any hints since you can't resolve the new location. One thing I've done in my current app that has reduced the pain of this issue is to add an extended attribute to any resource I store a bookmark for. Doing this at least lets me have the user choose a folder to search for previously associated resources.

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

Frustrating limitations, but bookmarks still win over storing static paths.

这篇关于处理陈旧的NSURL书签的正确方法是什么?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆