我指的是WWDC 2014示例应用NewBox,用于文档提供程序扩展。 我正在使用NeBox应用程序中的以下代码,将文档从文档提供程序导入我的应用程序。
- (void)documentPicker:(UIDocumentPickerViewController *)controller didPickDocumentAtURL:(NSURL *)url {
BOOL startAccessingWorked = [url startAccessingSecurityScopedResource];
NSURL *ubiquityURL = [[NSFileManager defaultManager] URLForUbiquityContainerIdentifier:nil];
NSLog(@"ubiquityURL %@",ubiquityURL);
NSLog(@"start %d",startAccessingWorked);
NSFileCoordinator *fileCoordinator = [[NSFileCoordinator alloc] init];
NSError *error;
[fileCoordinator coordinateReadingItemAtURL:url options:0 error:&error byAccessor:^(NSURL *newURL) {
NSData *data = [NSData dataWithContentsOfURL:newURL];
NSLog(@"error %@",error);
NSLog(@"data %@",data);
}];
[url stopAccessingSecurityScopedResource];
}
App完全挂起了coordinateReadingItemAtURL方法。 任何输入都会有所帮助。
答案 0 :(得分:1)
我在NewBox应用程序中也发现了这个问题,并决定跟踪它。因此,此应用程序中有两个扩展名:文档选择器和文件提供程序。长话短说,两者在尝试访问应用文档存储文件夹中的文件时存在竞争条件。
在我看来,追踪问题的最简单方法是将NSLog()
放在一堆位置。但问题是,扩展程序生成的调试输出在Xcode控制台中不可见。好消息是您可以通过单击 Debug - >在 iOS模拟器应用程序中打开控制台。打开系统日志菜单。这将显示各种调试消息,包括由扩展生成的消息。您可以找到有关扩展调试here的更多信息。
通过使用此方法,可以轻松地意识到执行卡在文件提供程序的startProvidingItemAtURL
方法中。更具体地说,以下行导致死锁:
[self.fileCoordinator coordinateWritingItemAtURL:url options:0 error:&error byAccessor:^(NSURL *newURL) {
为什么?请查看coordinateWritingItemAtURL
的文档:
如果url参数指定了一个文件: 此方法等待完全相同文件的其他读者和编写者完成正在进行的操作。
您提到的函数documentPicker
调用了一个读取操作,该操作又触发了写入操作。这是一个僵局。我想解决它的最简单方法是避免在文件提供程序中使用coordinateWritingItemAtURL
。
答案 1 :(得分:0)
根据文件:
这些方法中的每一个在同一个线程上调用传入的访问器块之前在它们被调用的同一线程上同步等待,而不是异步等待并在特定队列上调度块的调用。
答案 2 :(得分:0)
Apple建议您不要在此方法中使用文件协调。系统已经保证在执行此方法时没有其他进程可以访问该文件。这是造成这种僵局的唯一原因。
有关详细信息,请参阅this documentation。
答案 3 :(得分:0)
您也可以使用块。块工作太快,挂起问题就会得到解决。
第1步:获取
的全局变量UIDocumentPickerViewController *documentPicker;
也是decalre
typedef void(^myCompletion)(BOOL);
步骤2:编写一个分配发生的方法,并在完成时发送回调
-(void) allocateDocumentPicker:(myCompletion) compblock{
//do stuff
documentPicker = [[UIDocumentPickerViewController alloc] initWithDocumentTypes:@[@"public.content"]
inMode:UIDocumentPickerModeImport];
documentPicker.delegate = self;
documentPicker.modalPresentationStyle = UIModalPresentationFormSheet;
compblock(YES);
}
步骤3:每次要打开作曲家时调用分配的方法,但在接收完成时将其显示为YES。
-(IBAction)attachmentButtonClicked:(id)sender{
[self allocateDocumentPicker:^(BOOL finished) {
if(finished){
[self.parentScreen presentViewController:documentPicker animated:YES completion:nil];
}
}];
}
创建自己的块的简单语法,从此链接获取参考 Custom completion block for my own method