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

2024-03-18

这是后续访问 Mac 沙盒应用程序中的 sidecar 文件 https://stackoverflow.com/q/14772480/560648.

虽然答案中没有涵盖,但苹果文档告诉我们,要访问“相关文件”,我们必须使用NSFileCoordinator用于访问(ref https://developer.apple.com/library/archive/documentation/Security/Conceptual/AppSandboxDesignGuide/AppSandboxInDepth/AppSandboxInDepth.html).

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

对于正常的文件访问这不是问题:使用std::ifstream to 打开先前从“打开”面板中选择的文件 https://developer.apple.com/documentation/bundleresources/entitlements/com_apple_security_files_user-selected_read-only?language=objc似乎在应用程序实例的剩余生命周期中都有效。

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

添加了一个NSIsRelatedItemType到我的应用程序的 plist(如链接答案中所示),我在前端可以做的最少的事情是什么,大概是在打开“主”/请求的文件之后立即执行,这样我以后也可以使用std::ifstream打开相关的 sidecar 文件?关于这个主题的文档似乎有点稀疏......

也许我最好的选择是执行一次性提示,让用户授权访问封装目录,并将生成的权利保存为应用程序范围的书签(ref https://stackoverflow.com/a/48785789/560648)但这又不像我想要的那么透明。面对这样的请求,用户或许也会有点“害怕”。


不,因为操作系统[可能]实际上会将文件复制到不同的位置以便为您提供对其的访问权限,因此您必须使用NSFileCoordinator.

但一切并没有失去!有一个技巧:即使你的后端代码被设计为可移植的,如果你设置了文件读取.cpp要成为 Xcode 中的“Objective-C++ Source”,您可以使用 Foundation 功能(#import <Foundation/Foundation.h>) 在那里。

因此,无论您当前在何处实例化并读取std::ifstream, 有一个#if defined(PLATFORM_MAC_OS_X)(或其他什么),然后在其中用以下内容包装您的文件读取NSFileCoordinator code.

Up top:

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

本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)

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

随机推荐