从安全范围的书签解析 NSURL 时,如果用户已重命名或移动该文件或文件夹,则该书签将过时。苹果的文档对于陈旧性有这样的描述:
isStale
返回时,如果是,则书签数据已过时。你的应用程序应该
使用返回的 URL 创建一个新书签并用它代替
现有书签的任何存储副本。
不幸的是,这对我来说很少起作用。它可能在 5% 的时间内有效。试图使用返回的 URL 创建新书签导致错误(代码 256),并且在控制台中查看会显示一条来自 sandboxd 的消息,指出更新的 URL 上拒绝文件读取数据。
Note如果重新生成书签确实有效,则似乎只有在第一次重新生成时才有效。如果再次移动/重命名文件夹/文件,它似乎永远不会起作用。
我最初如何创建和存储书签
-(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, and com.apple.security.app-sandbox在我的权利文件中全部设置为 true。