我使用此代码将一些PDF数据保存到文件中,使用“打开方式”菜单将其发送到另一个应用程序,然后在完成后删除该文件:
- (void)openIn:(NSData *)fileData {
// save the PDF data to a temporary file
NSString *fileName = [NSString stringWithFormat:@"%@.pdf", self.name];
NSString *filePath = [NSString stringWithFormat:@"%@/Documents/%@", NSHomeDirectory(), fileName];
BOOL result = [fileData writeToFile:filePath atomically:TRUE];
if (result) {
NSURL *URL = [NSURL fileURLWithPath:filePath];
UIDocumentInteractionController *controller = [[UIDocumentInteractionController interactionControllerWithURL:URL] retain];
controller.delegate = self;
[controller presentOpenInMenuFromBarButtonItem:self.openInButton animated:TRUE];
}
}
- (void)documentInteractionControllerDidDismissOpenInMenu:(UIDocumentInteractionController *)controller {
// when the document interaction controller finishes, delete the temporary file
NSString *fileName = [NSString stringWithFormat:@"%@.pdf", self.name];
NSString *filePath = [NSString stringWithFormat:@"%@/Documents/%@", NSHomeDirectory(), fileName];
[[NSFileManager defaultManager] removeItemAtPath:filePath error:nil];
}
这在iOS 8之前一直运行正常。现在,文件已创建,我可以验证它包含正确的内容,出现打开菜单,我可以选择一个应用程序,并且委托方法运行并清理文件。但是,不是iOS切换到所选应用程序并将文件复制到之前,当我选择应用程序时,打开输入菜单就会关闭,而且文件不会被复制。
如果我给UIDocumentInteractionController一个现有文件,这是有效的。如果我使用提供的fileData但将目标文件名更改为现有文件的文件名,它也可以工作。这表明存在权限问题 - 就像在iOS 8中使用UIDocumentInteractionController无法读取的默认权限创建新文件一样。
有谁知道发生了什么以及如何解决这个问题?
答案 0 :(得分:7)
看起来iOS 8中的操作顺序略有变化.DidDismissOpenInMenu曾经在文件发送完成后运行,但现在它在文件开始发送后运行。这意味着我的清理代码有时会在文件完成发送之前运行,不会发送任何文件。在注意到较小的文件被发送好后,我想出了这个;显然,在我的清理代码获得之前,对较小文件的处理已经完成,但是对较大文件的处理却没有。
为了确保正确的计时,还要清理用户打开DocumentInteractionController时创建的文件,然后在不做任何事情的情况下解除控制器,我改变了我的方法:
- (void)openIn:(NSData *)fileData {
// save the PDF data to a temporary file
NSString *fileName = [NSString stringWithFormat:@"%@.pdf", self.name];
NSString *filePath = [NSString stringWithFormat:@"%@/Documents/%@", NSHomeDirectory(), fileName];
BOOL result = [fileData writeToFile:filePath atomically:TRUE];
if (result) {
self.sendingFile = FALSE;
NSURL *URL = [NSURL fileURLWithPath:filePath];
UIDocumentInteractionController *controller = [[UIDocumentInteractionController interactionControllerWithURL:URL] retain];
controller.delegate = self;
[controller presentOpenInMenuFromBarButtonItem:self.openInButton animated:TRUE];
}
}
- (void)documentInteractionController:(UIDocumentInteractionController *)controller willBeginSendingToApplication:(NSString *)application {
// the user chose to send the file, so we shouldn't clean it up until that's done
self.sendingFile = TRUE;
}
- (void)documentInteractionControllerDidDismissOpenInMenu:(UIDocumentInteractionController *)controller {
if (!self.sendingFile) {
// the user didn't choose to send the file, so we can clean it up now
[self openInCleanup];
}
}
- (void)documentInteractionController:(UIDocumentInteractionController *)controller didEndSendingToApplication:(NSString *)application {
// the user chose to send the file, and the sending is finished, so we can clean it up now
[self openInCleanup];
self.sendingFile = FALSE;
}
- (void)openInCleanup {
// delete the temporary file
NSString *fileName = [NSString stringWithFormat:@"%@.pdf", self.name];
NSString *filePath = [NSString stringWithFormat:@"%@/Documents/%@", NSHomeDirectory(), fileName];
[[NSFileManager defaultManager] removeItemAtPath:filePath error:nil];
}
iOS 11更新
在iOS 11之前,操作系统似乎保留了该文件的副本,直到接收应用程序完成读取,即使我的清理功能在文件从我的应用程序发出后立即运行。在iOS 11中,此更改并且接收应用程序无法读取文件,因为我的应用程序在完成之前将其删除。所以现在不是将临时文件保存到Documents并使用openInCleanup
方法立即删除它,而是将临时文件保存到tmp并在下次启动应用程序时清空tmp文件夹。此方法也适用于较旧的iOS版本。只需删除openInCleanup
,在路径中将文档更改为tmp,然后将其添加到applicationDidFinishLaunching
:
// clear the tmp directory, which will contain any files saved for Open In
NSString *tmpDirectory = [NSString stringWithFormat:@"%@/tmp", NSHomeDirectory()];
NSArray *tmpFiles = [[NSFileManager defaultManager] contentsOfDirectoryAtPath:tmpDirectory error:NULL];
for (NSString *tmpFile in tmpFiles) {
[[NSFileManager defaultManager] removeItemAtPath:[NSString stringWithFormat:@"%@/%@", tmpDirectory, tmpFile] error:NULL];
}
答案 1 :(得分:1)
阅读这篇文章后,我已经希望找到解决类似问题的方法:
对我来说,从iOS 8开始,共享仅适用于Mail.app。 Dropbox等失败了。
原来这是别的东西:
在我的interactionController上,我设置了一个这样的注释:
interactionController.annotation = @"Some text"
由于未知原因,这会阻止Dropbox打开。没有错误消息或任何内容。删除此行解决了这个问题。