UIDocumentPickerViewController NewBox应用程序挂起

UIDocumentPickerViewController NewBox应用程序挂起,document,ios8,ios-app-extension,Document,Ios8,Ios App Extension,我指的是WWDC 2014样本应用程序NewBox,用于文档提供商扩展。 我正在使用NeBox应用程序中的以下代码,将文档从文档提供程序导入我的应用程序 - (void)documentPicker:(UIDocumentPickerViewController *)controller didPickDocumentAtURL:(NSURL *)url { BOOL startAccessingWorked = [url startAccessingSecurityScopedResource

我指的是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]; 
}

应用程序完全挂起,用于协调ADINGITEMATURL方法。 任何输入都会有帮助。

根据文档:

这些方法中的每一个都在同一个线程上同步等待,然后在同一个线程上调用传入的访问器块,而不是在特定队列上异步等待和调度块调用


我在NewBox应用程序中也注意到了这个问题,并决定跟踪它。因此,该应用程序中有两个扩展名:文档选择器和文件提供程序。长话短说,当他们试图访问应用程序文档存储文件夹中的文件时,两者之间存在竞争条件

在我看来,追踪问题的最简单方法是将
NSLog()
放在一堆位置。但问题是,扩展生成的调试输出在Xcode控制台中不可见。好消息是,您可以通过单击调试->打开系统日志菜单在iOS模拟器应用程序中打开控制台。这将显示各种调试消息,包括由扩展生成的消息。您可以找到有关扩展调试的更多信息

通过使用此方法,您可以很容易地意识到执行会卡在文件提供程序的
startProvisingItemAttribute
方法中。更具体地说,以下行会导致死锁:

[self.fileCoordinator coordinateWritingItemAtURL:url options:0 error:&error byAccessor:^(NSURL *newURL) {
为什么呢?请查看
协调写入项属性的文档:

如果url参数指定了一个文件: 此方法等待完全相同文件的其他读取器和写入器完成正在进行的操作


您提到的函数
documentPicker
调用读取操作,而读取操作又会触发写入操作。这是一个僵局。我想最简单的修复方法是避免在文件提供程序中使用
CoordinateWritingItemAttribute

苹果建议您不要在该方法中使用文件协调。系统已经保证在执行此方法时,没有其他进程可以访问该文件。这是造成僵局的唯一原因


有关更多详细信息,请参阅。

您也可以使用block。块工作太快,挂起问题将得到解决

步骤1:获取的全局变量

UIDocumentPickerViewController *documentPicker; 
也贴花

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:每次要打开编写器时调用分配发生的方法,但在接收到完成时将其显示为“是”

-(IBAction)attachmentButtonClicked:(id)sender{

    [self allocateDocumentPicker:^(BOOL finished) {
        if(finished){
            [self.parentScreen presentViewController:documentPicker animated:YES completion:nil];
        }
    }];
}
创建自己的块的简单语法,请参考此链接