我有一个符合NSFilePresenter协议的对象,该协议代表我基于文档的应用程序文档包.当在包内创建一个新文件时,要么以编程方式使用NSFileManager和正确的NSFileCoordination方法,要么通过Finder我只得到-presentedSubitemDidChangeAtURL:
事件,但在这种情况下看起来并不那么明显-presentedSubitemDidAppearAtURL:
.
这是预期的行为还是我做错了什么?
-presentedSubitemDidAppearAtURL:
NSFilePresenter中的评论明确指出:
通知已添加目录包含的文件或目录.如果此方法未实现但是
-presentedItemDidChange
,并且该目录实际上是文件包,则文件协调机制将调用-presentedItemDidChange
.
我正在设置NSFileCoordinator
并NSFilePresenter
在我的应用程序中,因此我可以安全地从AppleWatch应用程序执行文件IO.在我的代码中有一些地方我快速连续几次写入文件.这本身就是一个问题,我正在努力纠正它,但我注意到这个过程中有些奇怪的行为.
我像这样包装我的写作:
//In a class that implements NSFilePresenter:
NSFileCoordinator *coord = [[NSFileCoordinator alloc]initWithFilePresenter:self];
[coord coordinateWritingItemAtURL:self.presentedItemUrl options:0 error:nil byAccessor:^(NSURL *url)
{
//do my writing here using CFWriteStreamRef or NSOutputStream
}];
Run Code Online (Sandbox Code Playgroud)
在第一次写入时,写入块在1 ms内发生.但在那之后,调用coordinateWritingItemAtURL
和正在执行的写入块之间大约有0.5秒的延迟.
这是预期的行为吗?
一些文档用于批处理操作NSFileCoordinator
并且NSFilePresenter
说prepareForReadingItemsAtURLs:writingItemsAtURLs:options:error:byAccessor:
用于批处理操作,但是当我不进行批处理时,得到如此长的延迟似乎很奇怪.
更新:这也发生在阅读上.
更新2: 这是一个重现问题的示例项目.
我有一个 iOS 应用程序,它试图从外部存储设备读取文件而不将它们导入应用程序的沙箱。
我已按照此处概述的 Apple 文档来执行此操作-
我能够检索选定的目录(位于通过 Lightning 端口连接的外部存储设备上)并枚举目录中的文件。
但是,当我尝试按照推荐的模式对这些文件执行某些操作时,我遇到了失败,并且基本上会出现该文件的权限错误。
let shouldStopAccessing = pickedFolderURL.startAccessingSecurityScopedResource()
defer {
if shouldStopAccessing {
pickedFolderURL.stopAccessingSecurityScopedResource()
}
}
var coordinatedError:NSError?
NSFileCoordinator().coordinate(readingItemAt: pickedFolderURL, error: &coordinatedError) { (folderURL) in
let keys : [URLResourceKey] = [.isDirectoryKey]
let fileList = FileManager.default.enumerator(at: pickedFolderURL, includingPropertiesForKeys: keys)!
for case let file as URL in fileList {
if !file.hasDirectoryPath {
do {
// Start accessing a security-scoped resource.
guard file.startAccessingSecurityScopedResource() else {
// Handle the failure here.
//THIS ALWAYS FAILS!!
return
}
// …
Run Code Online (Sandbox Code Playgroud) ios nsfilecoordinator swift uidocumentpickerviewcontroller ios13
我已经完全实现了NSFilePresenter
协议,NSFileCoordinator
用于跟踪对导入的文件夹/文件树所做的外部更改.它通常有效.
但是,我仍然有点困惑.
presentedSubitemDidChangeAtURL:
,presentedSubitemAtURL:didMoveToURL:
并且presentedItemDidChange
是唯一被调用的人presentedItemDidChange
(在其他情况下显然也会调用)我错过了什么?
不应该presentedItemDidGainVersion:
或savePresentedItemChangesWithCompletionHandler:
被叫?
任何帮助或指示都非常受欢迎!:)
我正在尝试下载文件夹层次结构中包含的文件UIDocumentPickerController
.我用我从获取URL documentPicker:DidPickDocumentsAtURLs:
用NSFileCoordinator
.
对于iCloud Drive文件提供程序提供的文件夹,它在访问块中提供的URL显然是.zip文件 - 如果文件最初未下载 - 仅包含foo.icloud
归档NSURL的文件.如何在压缩过程之前确保已下载这些文件?
我是否应该手动取消归档并将它们再次送入NSFileCoordinator
?或者我需要使用startDownloadingUbiquitousItemAtURL:error:
?我认为使用它UIDocumentPickerController
应该让我摆脱所有的手动协调逻辑.
我错过了什么?
ios nsfilecoordinator uidocumentpickervc icloud-drive uidocumentpickerviewcontroller
我正在编写一个小型macOS应用程序,希望在其中查看文件夹中的更改。它不需要监视子文件夹,我只想在文件添加到文件夹或删除文件时收到通知。
看起来NSFileCoordinator
和/或NSFilePresenter
可以用来实现这一目标,但是我无法理解如何使用它们来实现这一目标。
理想情况下,无需包含第三方框架即可解决此问题。
由于sqlite执行事务的方式(使用wal或journal文件),我有很多麻烦将我的sqlite代码移植到App Store.Apple文档的相关部分是:
您的应用程序需要能够打开或保存具有相同名称和不同扩展名的多个相关文件(例如,自动打开与电影文件同名的字幕文件,或允许SQLite日志文件).要访问该辅助文件,请创建符合NSFilePresenter协议的类.此对象应将主文件的URL作为其primaryPresentedItemURL属性提供,并应将辅助文件的URL作为其presentItemURL属性提供.用户打开主文件后,文件presenter对象应调用NSFileCoordinator类上的addFilePresenter:class方法来注册自己.
Apple DTS为我提供了以下代码:
- (void)openSQLiteFileAtURL:(NSURL *)fileURL {
NSFileCoordinator *fc = [[NSFileCoordinator alloc] initWithFilePresenter:nil];
[fc coordinateReadingItemAtURL:fileURL options:0 error:NULL byAccessor:^(NSURL *newURL) {
sqlite3 *db = NULL;
char *zErrMsg = 0;
[SQLiteRelatedItemPresenter addPresentersForURL:newURL];
int rc = sqlite3_open_v2([[newURL path] fileSystemRepresentation], &db, SQLITE_OPEN_READWRITE | SQLITE_OPEN_CREATE, NULL);
NSLog(@"open %@ = %d", [newURL path], rc);
rc = sqlite3_exec(db, "CREATE TABLE foo (col1 INTEGER);", callback, 0, &zErrMsg);
if( rc!=SQLITE_OK ){
NSLog(@"SQL error: %s\n", zErrMsg);
sqlite3_free(zErrMsg);
}
// more sqlite code here
sqlite3_close(db);
}];
return;
}
Run Code Online (Sandbox Code Playgroud)
其中SQLiteRelatedItemPresenter是: …
使用NSFileCoordinator编写文件时,我需要指定正确的NSFileCoordinatorWritingOptions.虽然详细解释了,但我不知道何时使用哪一个.可用选项包括:
例如,如果我想创建一个文件(例如plist),那么哪个选项是正确的?我修改文件时哪一个?
有人可以解释NSFileCoordinatorWritingOptions以便更好地理解吗?
我正在尝试编写一个简单的(玩具)程序,它使用NSFilePresenter和NSFileCoordinator方法来监视文件的变化.
该程序包含一个文本视图,用于加载(硬编码)文本文件和一个按钮,该文件将保存文件并进行任何更改.我的想法是我有两个实例正在运行,并且在一个实例中保存将导致另一个实例重新加载已更改的文件.
加载和保存文件工作正常,但从不调用NSFilePresenter方法.它都基于一个名为FileManager的类,它实现了NSFilePresenter协议.代码如下:
接口:
@interface FileManager : NSObject <NSFilePresenter>
@property (unsafe_unretained) IBOutlet NSTextView *textView;
- (void) saveFile;
- (void) reloadFile;
@end
Run Code Online (Sandbox Code Playgroud)
执行:
@implementation FileManager
{
NSOperationQueue* queue;
NSURL* fileURL;
}
- (id) init {
self = [super init];
if (self) {
self->queue = [NSOperationQueue new];
self->fileURL = [NSURL URLWithString:@"/Users/Jonathan/file.txt"];
[NSFileCoordinator addFilePresenter:self];
}
return self;
}
- (NSURL*) presentedItemURL {
NSLog(@"presentedItemURL");
return self->fileURL;
}
- (NSOperationQueue*) presentedItemOperationQueue {
NSLog(@"presentedItemOperationQueue");
return self->queue;
}
- (void) saveFile {
NSFileCoordinator* coordinator = [[NSFileCoordinator alloc] …
Run Code Online (Sandbox Code Playgroud) 看来 NSFileCoordinator 尽管是一个非常重要的类,但尚未获得任何 Swiftification。没有给予它任何async
替代方案;您必须提供一个完成处理程序。此外,它需要一个 NSErrorPointer 而不是被标记throws
,并且不能在完成处理程序中引用被指向者:
let url = URL(fileURLWithPath: "fakepath")
var error: NSError?
NSFileCoordinator().coordinate(readingItemAt: url, error: &error) { url in
let theError = error
print(theError as Any)
}
Run Code Online (Sandbox Code Playgroud)
这会导致错误:“同时访问error
,但修改需要独占访问。”
如果我无法从块内部访问错误,那它有什么用呢?我应该如何访问它?当然不是在区块之后;完成处理程序是异步调用的(因为我们必须等到可以进行协调访问),因此在块之后,nil
即使实际上存在错误,错误也将始终存在。
(我注意到苹果自己的示例代码根本不检查其变量的值,从而绕过了这个问题error
。)
到目前为止我所拥有的是创建新本地文件并删除iCloud文件的代码.
是否可以重命名iCloud文档,以便它保留在iCloud中?
GarageBand可以做到.可以重命名iCloud歌曲.重命名完成后,歌曲仍然在iCloud中.然而,GarageBand是Apple应用程序,因此它可能使用私有api.
我目前的代码:
- (void)moveFrom:(NSURL*)sourceURL
moveTo:(NSString*)destinationName
completion:(void (^)())completion
{
MyDocument *document = [[MyDocument alloc] initWithFileURL:sourceURL];
[document openWithCompletionHandler:^(BOOL success)
{
NSURL *fileURL = [self.localRoot URLByAppendingPathComponent:destinationName];
DLog(@"Create %@", fileURL);
[document saveToURL:fileURL
forSaveOperation:UIDocumentSaveForCreating
completionHandler:^(BOOL success)
{
NSLog(@"Saved %@", fileURL);
[document closeWithCompletionHandler:^(BOOL success) {
// Delete the old document from a secondary thread
dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^()
{
NSFileCoordinator* fileCoordinator = [[NSFileCoordinator alloc] initWithFilePresenter:nil];
[fileCoordinator coordinateWritingItemAtURL:sourceURL
options:NSFileCoordinatorWritingForDeleting
error:nil
byAccessor:^(NSURL* writingURL) {
NSFileManager* fileManager = [[NSFileManager alloc] init];
[fileManager removeItemAtURL:writingURL error:nil];
DLog(@"Deleted %@", sourceURL); …
Run Code Online (Sandbox Code Playgroud) 我正在寻找一种更好的方法从我的iCloud容器下载一堆文件到我的沙箱.这是我目前使用的:
for (FileAttachments *fileLink in items) {
NSURL *cloudFileURL = [fileLink urlForCloudAttachmentWithName];
NSURL *fileURL = [backupCloudLocalDirectoryURL URLByAppendingPathComponent: fileLink.fileName];
NSFileCoordinator *fileCoordinator = [[NSFileCoordinator alloc] initWithFilePresenter:nil];
[fileCoordinator coordinateReadingItemAtURL:fileURL options:NSFileCoordinatorReadingWithoutChanges error:&error
byAccessor:^(NSURL *newURL) {
NSError *blockError = nil;
[fileManager copyItemAtURL:cloudFileURL toURL:fileURL error:&blockError];
}];
}
}
Run Code Online (Sandbox Code Playgroud)
以这种方式复制iCloud项目有什么问题吗?在制作中,我有一些用户抱怨所有文件都没有下载.是否更好地使用NSFileManager's startDownloadingUbiquitousItemAtURL:error
?如果是这样,为什么?谢谢.
cocoa ×7
ios ×5
objective-c ×5
icloud ×3
swift ×3
uidocumentpickerviewcontroller ×2
icloud-drive ×1
ios13 ×1
macos ×1
sqlite ×1
uidocument ×1