这是Access sidecar files in a Mac sandboxed app的后续行动。
尽管这里的答案没有涵盖,但是Apple文档告诉我们,要访问“相关文件”,我们必须使用NSFileCoordinator
进行访问(ref)。
这对于我的需求来说有点沉重,并且造成了体系结构问题,因为实际的文件访问位于我的后端代码中,而不是苹果图书馆的设施。如果可以帮助,我不需要使用NSFileCoordinator
来获取相关文件的内容。我也不想要求用户手动标识sidecar文件(如果没有其他要求,这对于批处理而言将是一个糟糕的工作流程)。我只想告诉沙盒“没关系,在用户选择File.ABC之后,此应用程序可以打开与之相关的File.XYZ”。
对于普通文件访问,这不是问题:在应用程序实例的整个生命周期中,使用std::ifstream
到open a file that's been previously selected from an Open panel似乎都可以使用。
但是打开“相关文件”似乎更受限制。
已在我的应用程序的plist中添加了NSIsRelatedItemType
(如链接的答案所示),我大概在打开“主要” /请求的文件后立即可以在前端执行的最小操作是,以后还可以使用std::ifstream
打开相关的sidecar文件吗?文档在这个主题上似乎有点稀疏...
也许我最好的选择是执行一次提示,提示用户授权访问封装目录,并将产生的权利保存为应用程序作用域的书签(ref),但这又不像我那么透明想要。用户面对这样的请求可能也有些“吓人”。
否,因为操作系统会[潜在地]实际上将文件复制到其他位置以便向您提供对其的访问权限,所以您必须使用NSFileCoordinator
。
但是一切都不会丢失!有一个技巧:即使您的后端代码被设计为可移植的,但是如果您在Xcode中将文件读取.cpp
设置为“ Objective-C ++ Source”,则可以使用Foundation功能(#import <Foundation/Foundation.h>
)那里。
因此,无论您当前在何处实例化并从std::ifstream
读取数据,都需要一个#if defined(PLATFORM_MAC_OS_X)
(或其他内容),然后在其中放入NSFileCoordinator
代码来包装文件读取的内容。
上方:
#ifdef PLATFORM_MAC_OS_X
#import <Foundation/Foundation.h>
@interface SidecarPresenter : NSObject<NSFilePresenter>
@property(readwrite, copy) NSURL* presentedItemURL;
@property(readwrite, copy) NSURL* primaryPresentedItemURL;
@property(readwrite, assign) NSOperationQueue* presentedItemOperationQueue;
-(instancetype)initWithImageUrl:(NSURL*)imageUrl andSidecarExtension:(NSString*)newExt;
@end
@implementation SidecarPresenter
- (instancetype)initWithImageUrl:(NSURL*)imageUrl andSidecarExtension:(NSString*)newExt
{
self = [super init];
if (self)
{
[self setPrimaryPresentedItemURL:imageURL];
[self setPresentedItemURL:[[imageUrl URLByDeletingPathExtension] URLByAppendingPathExtension:newExt]];
[self setPresentedItemOperationQueue:[NSOperationQueue mainQueue]];
}
return self;
}
- (void)dealloc
{
[_primaryPresentedItemURL release];
[_presentedItemURL release];
[super dealloc];
}
@end
#endif
以及以后:
#ifdef PLATFORM_MAC_OS_X
SidecarPresenter* presenter = [SidecarPresenter alloc];
[presenter initWithImageUrl:[NSURL fileURLWithPath:documentFilename]
andSidecarExtension:sidecarExtension]];
[presenter autorelease];
[NSFileCoordinator addFilePresenter:presenter];
NSFileCoordinator* coordinator = [[[NSFileCoordinator alloc] initWithFilePresenter:presenter] autorelease];
NSError* error = nil;
[coordinator coordinateReadingItemAtURL:presenter.presentedItemURL
options:NSFileCoordinatorReadingWithoutChanges
error:&error
byAccessor:^(NSURL* newURL)
{
std::ifstream strm([newURL fileSystemRepresentation]);
foo(strm);
}];
[NSFileCoordinator removeFilePresenter:presenter];
#else
std::ifstream strm(documentFilename);
foo(strm);
#endif
这样,在后端和前端之间就不会出现来回乒乓的现象。而且lambda是同步调用的,因此您也不必担心竞争状况(可能只是一点额外的延迟)。唯一的代价是特定于平台的泄漏,但至少隐藏在预处理器指令中。