有没有NSFileCoordinator的替代方案,可以在沙箱中打开相关文件? [英] Is there an alternative to NSFileCoordinator for opening related files in a sandbox?
问题描述
尽管那里的答案未涵盖其中,但Apple文档告诉我们,要访问相关文件",我们必须使用NSFileCoordinator
进行访问(
Though not covered in the answer there, the Apple docs teach us that to access a "related file" we must use an NSFileCoordinator
for access (ref).
这对于我的需求来说有点沉重,并且造成了体系结构问题,因为实际的文件访问位于我的后端代码中,而不是苹果图书馆的设施.如果可以帮助,我不需要使用NSFileCoordinator
来获取相关文件的内容.我也不想要求用户手动标识sidecar文件(如果没有其他要求,这对于批处理来说将是一个糟糕的工作流程).我只想告诉沙盒没关系,用户选择File.ABC之后,此应用程序可以打开与之相关的File.XYZ".
This is a little heavy for my needs, and poses an architectural problem, since the actual file access is in my back-end code, away from the reaches of the Apple library facilities. I don't want to have to use the NSFileCoordinator
for obtaining the related file's content, if I can help it. I don't want to require my users to manually identify the sidecar file either (if nothing else, this would be a bad workflow for batch processing). I just want to tell the sandbox "this is okay, this app can open such-and-such a related File.XYZ after the user chose File.ABC".
对于普通文件访问来说,这不是问题:使用std::ifstream
来打开以前从打开"面板中选择的文件似乎可以在应用实例的整个生命周期中发挥作用.
For normal file accesses this isn't a problem: using an std::ifstream
to open a file that's been previously selected from an Open panel seems to work for remainder of the app instance's lifetime.
但是打开相关文件"似乎受到更多限制.
But opening a "related file" seems to be more limited.
已经在我的应用程序的plist中添加了NSIsRelatedItemType
(如链接的答案所示),我大概可以在打开主要"/请求的文件后立即在前端执行的最小操作是,以后我还可以使用std::ifstream
打开相关的sidecar文件吗?在这个主题上,文档显得有些稀疏…
Having added a NSIsRelatedItemType
to my app's plist (as indicated in the linked answer), what is the minimal thing I can do in the front-end, presumably immediately after opening the "primary"/requested file, such that I can also later use an std::ifstream
to open a related sidecar file? The documentation seems a little sparse on this subject…
也许我最好的选择是执行一次提示,提示用户授权访问封装目录,并将产生的权利保存为应用程序范围的书签(
Perhaps my best bet is to perform a one-time prompt for the user to authorise access to the encapsulating directory, and save the resulting entitlement as an app-scoped bookmark (ref) but again that's not quite as transparent as I'd like. It would also be perhaps a little "scary" for users to be confronted with such a request.
推荐答案
否,因为操作系统实际上会[潜在地]将文件复制到其他位置,以便为您提供对其的访问权限,因此您必须使用
No, because the OS will [potentially] actually copy the file to a different location in order to provide you with access to it, so you must use NSFileCoordinator
.
但是一切并没有丢失!有一个技巧:即使您的后端代码被设计为可移植的,但是如果您在Xcode中将文件读取.cpp
设置为"Objective-C ++ Source",则可以使用Foundation功能(#import <Foundation/Foundation.h>
)在那里.
But all is not lost! There is a hack: even if your back-end code is designed to be portable, if you set the file-reading .cpp
to be "Objective-C++ Source" in Xcode, you can use Foundation features (#import <Foundation/Foundation.h>
) right there.
因此,无论您当前在何处实例化和读取std::ifstream
,都需要一个#if defined(PLATFORM_MAC_OS_X)
(或其他任何内容),然后在其中放入NSFileCoordinator
代码来包装文件.
So wherever you currently instantiate and read-from an std::ifstream
, have an #if defined(PLATFORM_MAC_OS_X)
(or whatever) and, inside that, wrap your file-reading with the NSFileCoordinator
code.
顶部:
#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是同步调用的,因此您也不必担心竞争状况(可能只是一点额外的延迟).唯一的代价就是平台特定的泄漏,但至少隐藏在预处理器指令中.
In this way, there's no ping-ponging back and forth between the back- and front-end. And the lambda is invoked synchronously so you don't have to worry about race conditions, either (just a bit of extra latency, potentially). The only cost is a bit of platform-specific leakage but at least it's hidden away inside a preprocessor directive.
这篇关于有没有NSFileCoordinator的替代方案,可以在沙箱中打开相关文件?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!