从安全范围的书签解析 NSURL 时,如果用户重命名或移动了该文件或文件夹,则该书签将过时。Apple 的文件对陈旧性进行了说明:
是陈旧的
返回时,如果是,则书签数据已过时。您的应用应使用返回的 URL 创建一个新书签,并使用它来代替现有书签的任何存储副本。
不幸的是,这对我来说很少有用。它可能有 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在我的权利文件中。