Cocoa 处理过时NSURL书签的正确方法是什么?
从安全范围的书签解析NSURL时,如果用户重命名或移动了该文件或文件夹,则书签将过时。苹果公司的文件说,关于陈腐: isStale 返回时,如果是,则书签数据已过时。你的应用应该 使用返回的URL创建一个新书签,并使用它代替 现有书签的任何存储副本 不幸的是,这很少适用于我。它可能在5%的时间内工作。尝试使用返回的URL创建新书签会导致错误,代码为256,在控制台中查看会显示来自sandboxd的消息,其中说拒绝更新URL上的文件读取数据 注意如果重新生成书签确实有效,它似乎只在第一次重新生成书签时有效。如果文件夹/文件再次被移动/重命名,它似乎永远不会起作用 我最初如何创建和存储书签Cocoa 处理过时NSURL书签的正确方法是什么?,cocoa,nsurl,security-scoped-bookmarks,Cocoa,Nsurl,Security Scoped Bookmarks,从安全范围的书签解析NSURL时,如果用户重命名或移动了该文件或文件夹,则书签将过时。苹果公司的文件说,关于陈腐: isStale 返回时,如果是,则书签数据已过时。你的应用应该 使用返回的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);
}
}
解析书签的代码
-(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替换过期书签。”
令人沮丧的限制,但书签仍然胜过存储静态路径。@user362515请确认,您是说,在10.11之前创建新书签时,旧书签解决了问题,但报告已过时且无法访问,您没有看到任何问题?具体来说,2号子弹不再是个问题了?如果是这样,那太好了!从OS X 10.11开始,从已解决的旧书签创建新的安全范围书签似乎没有问题。是的,只要在新书签上运行
startAccessingSecurityScopedResource
,持续时间为bookmarkDataWithOptions
。顺便说一句,重命名/移动文件的书签解析仅在同一卷上有效,这是有文档记录的。@user362515真棒,至少这是一些改进。我没有在文档中看到它说解析只能在原始卷上工作。我确实看到了它所说的对于无法装入的卷它将失败的地方。你有没有链接到你看到这个的确切位置?我实际上已经创建了一个单独的问题,与此相关