3

I am referring WWDC 2014 sample app NewBox for document provider extension. I am using following code from NeBox app, to import a document from Document Provider to my app.

- (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 totally hangs for coordinateReadingItemAtURL method. Any inputs will be helpful.

tejashri
  • 215
  • 2
  • 8

4 Answers4

1

I noticed this problem in NewBox app as well, and decided to trace it. So, there are two extensions in this app: Document Picker and File Provider. To make long story short, there is a race condition between the two when they try to access files within app's document storage folder.

In my opinion, the easiest method to trace down a problem is to put NSLog() in a bunch of locations. The problem is, however, that the debugging output generated by extension won't be visible in Xcode console. The good news is that you can open console in iOS Simulator app by clicking to Debug -> Open System Log menu. This will show all kinds of debugging messages, including those generated by extensions. You can find more about extension debugging here.

By using this method one can easily realize that execution gets stuck in File Provider's startProvidingItemAtURL method. More specifically, the following line causes a deadlock:

[self.fileCoordinator coordinateWritingItemAtURL:url options:0 error:&error byAccessor:^(NSURL *newURL) {

Why is that? Take a look at documentation for coordinateWritingItemAtURL:

If the url parameter specifies a file: This method waits for other readers and writers of the exact same file to finish in-progress actions.

Function documentPicker that you mentioned calls a read operation, which in its turn triggers a write operation. This is a deadlock. I guess the easiest way to fix it would be to avoid using coordinateWritingItemAtURL in File Provider.

Community
  • 1
  • 1
Alexey
  • 1,177
  • 2
  • 14
  • 23
0

As per documentation:

Each of these methods wait synchronously on the same thread they were invoked on before invoking the passed-in accessor block on the same thread, instead of waiting asynchronously and scheduling invocation of the block on a specific queue.

cescofry
  • 3,706
  • 3
  • 26
  • 22
0

Apple recommends that you not use file coordination inside this method. The system already guarantees that no other process can access the file while this method is executing. That's the sole reason for this deadlock.

Please refer to this documentation for more details.

pjmorse
  • 9,204
  • 9
  • 54
  • 124
Vsh
  • 81
  • 9
0

You can use block also. Block works too fast, hang problem will get resolve.

Step 1: Take global variable of

UIDocumentPickerViewController *documentPicker; 

also decalre

typedef void(^myCompletion)(BOOL);

Step 2: Write a method where allocation takes place and can send callback on completion

-(void) allocateDocumentPicker:(myCompletion) compblock{
    //do stuff
    documentPicker = [[UIDocumentPickerViewController alloc] initWithDocumentTypes:@[@"public.content"]
                                                                            inMode:UIDocumentPickerModeImport];
    documentPicker.delegate = self;
    documentPicker.modalPresentationStyle = UIModalPresentationFormSheet;
    compblock(YES);
}

Step 3: Call the method where allocation is taking place every time you want to open the composer but present it on receiving completion as YES.

-(IBAction)attachmentButtonClicked:(id)sender{

    [self allocateDocumentPicker:^(BOOL finished) {
        if(finished){
            [self.parentScreen presentViewController:documentPicker animated:YES completion:nil];
        }
    }];
}

Simple Syntax to create own block, take reference from this link Custom completion block for my own method

Community
  • 1
  • 1