繁体   English   中英

是否有替代 NSFileCoordinator 在沙箱中打开相关文件的方法?

[英]Is there an alternative to NSFileCoordinator for opening related files in a sandbox?

这是在 Mac 沙盒应用程序中访问 sidecar 文件的后续内容。

尽管那里的答案没有涵盖,但 Apple 文档告诉我们,要访问“相关文件”,我们必须使用NSFileCoordinator进行访问( ref )。

这对于我的需求来说有点沉重,并且会带来架构问题,因为实际的文件访问是在我的后端代码中,远离 Apple 库设施的范围。 如果可以的话,我不想使用NSFileCoordinator来获取相关文件的内容。 我也不想要求我的用户手动识别 sidecar 文件(如果不出意外,这对于批处理来说将是一个糟糕的工作流程)。 我只是想告诉沙箱“这没关系,这个应用程序可以在用户选择File.ABC后打开某某相关的File.XYZ”。

对于正常的文件访问,这不是问题:使用std::ifstream 打开先前从 Open 面板中选择的文件似乎在应用程序实例的剩余生命周期中都有效。

但是打开“相关文件”似乎更受限制。

在我的应用程序的 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 是同步调用的,因此您也不必担心竞争条件(可能只是一点额外的延迟)。 唯一的代价是一些特定于平台的泄漏,但至少它隐藏在预处理器指令中。

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM