c++ - 是否有替代 NSFileCoordinator 在沙箱中打开相关文件的方法?
问题描述
这是在 Mac 沙盒应用程序中访问附属文件的后续内容。
尽管那里的答案没有涵盖,但 Apple 文档告诉我们,要访问“相关文件”,我们必须使用NSFileCoordinator
for 访问(ref)。
这对我的需求来说有点繁重,并且带来了架构问题,因为实际的文件访问在我的后端代码中,远离 Apple 库设施的范围。如果可以的话,我不想使用NSFileCoordinator
来获取相关文件的内容。我也不想要求我的用户手动识别 sidecar 文件(如果没有别的,这对于批处理来说将是一个糟糕的工作流程)。我只是想告诉沙盒“这没关系,这个应用程序可以在用户选择File.ABC后打开某某相关的File.XYZ”。
对于正常的文件访问,这不是问题:使用std::ifstream
来打开以前从“打开”面板中选择的文件似乎在应用程序实例的剩余生命周期内都有效。
但是打开“相关文件”似乎更受限制。
在NSIsRelatedItemType
我的应用程序的 plist 中添加了一个(如链接答案中所示),我可以在前端做的最小的事情是什么,大概是在打开“主要”/请求的文件之后,这样我以后也可以使用std::ifstream
打开相关的边车文件?关于这个主题的文档似乎有点稀疏......
也许我最好的选择是执行一次提示,让用户授权访问封装目录,并将生成的权利保存为应用范围的书签 ( ref ),但这并不像我想要的那样透明。面对这样的请求,用户可能也会有点“害怕”。
解决方案
不,因为操作系统 [可能] 实际上会将文件复制到不同的位置,以便为您提供对其的访问权限,因此您必须使用NSFileCoordinator
.
但一切都没有丢失!有一个技巧:即使您的后端代码被设计为可移植的,如果您.cpp
在 Xcode 中将文件读取设置为“Objective-C++ Source”,您也可以在#import <Foundation/Foundation.h>
此处使用 Foundation 功能 ()。
因此,无论您当前在哪里实例化和读取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 是同步调用的,因此您也不必担心竞争条件(可能只是一点额外的延迟)。唯一的代价是一些特定于平台的泄漏,但至少它隐藏在预处理器指令中。
推荐阅读
- regex - 如何使用bash case语句否定字符串中某个字符的“正则表达式”模式
- javascript - Puppeteer:如何制作包含多个画布元素的页面部分的 pdf?
- ansible - 如何将多行 JSON 字符串传递给 ansible-playbook 的 --extra-vars
- php - CakePHP - Hotw 使用 FormHelper 生成具有多个属性的选择字段
- ios - CocoaPods 找不到 pod "AFNetworking" 的兼容版本:
- unity3d - Unity HUB 无法检测到手动下载的 Unity 版本
- regex - 正则表达式:从匹配的模式中排除字符串
- java - Spring Boot Data JPA 从存储过程接收多个输出参数
- ios - 无法调用非函数类型“对象”的值
- nginx - 无法禁用 X-frame 选项:nginx 中的同源