简体   繁体   中英

iOS8: UIDocumentPickerViewController get NSData

I have implement UIDocumentPickerViewController according docs and now trying to get NSData from picked file in delegate method, but [[NSData alloc] initWithContentsOfURL:] returns nil:

- (void)documentPicker:(UIDocumentPickerViewController *)controller didPickDocumentAtURL:(NSURL *)url{
    NSData* documentData = [[NSData alloc] initWithContentsOfURL:url];
    //documentData is nil
    documentData = [[NSData alloc] initWithContentsOfFile:[url path]];
    //documentData is still nil :(
}

I'm using Xcode6 beta6, iPhone simulator, document picker mode is UIDocumentPickerModeImport . Trying to retrieve documents saved to iCloude Drive.

Elaborating on @cescofry's answer a bit here regarding iWork files (.pages, .numbers, .key) so others won't have to rediscover the issue. (This will work for non iWork files as well.)

If you are pulling iWork files from iCloud, you need to worry about two primary things before you can get a valid NSData object. A) Security scope through a NSFileCoordinator object (as covered by @cescofry) and B) that iWork files are actually directories/bundles not single files. The options parameter you want for coordinateReadingItemAtURL: is NSFileCoordinatorReadingForUploading . This will read in single files as if you had used 0 , but will turn directories into zip files automatically. Strip off the .zip that is added on and you'll have a valid Pages/Numbers/Keynote file. (It's valid with it on too.)

[url startAccessingSecurityScopedResource];
NSFileCoordinator *coordinator = [[NSFileCoordinator alloc] init];
NSError *error;
__block NSData *fileData;

[coordinator coordinateReadingItemAtURL:url options:NSFileCoordinatorReadingForUploading error:&error byAccessor:^(NSURL *newURL) {
   // File name for use in writing the file out later
   NSString *fileName = [newURL lastPathComponent];
   NSString *fileExtension = [newURL pathExtension];

   if([fileExtension isEqualToString:@"zip"]) {
     if([[[newURL URLByDeletingPathExtension] pathExtension] isEqualToString:@"pages"] ||
        [[[newURL URLByDeletingPathExtension] pathExtension] isEqualToString:@"numbers"] ||
        [[[newURL URLByDeletingPathExtension] pathExtension] isEqualToString:@"key"] ) {
       // Remove .zip if it is an iWork file
       fileExtension = [[newURL URLByDeletingPathExtension] pathExtension];
       fileName = [[newURL URLByDeletingPathExtension] lastPathComponent];
     }
   }

   NSError *fileConversionError;
   fileData = [NSData dataWithContentsOfURL:newURL options:NSDataReadingUncached error:&fileConversionError];

   // Do something with the file data here

}
[url stopAccessingSecurityScopedResource];

Relevant Apple documentation on the NSFileCoordinator options here: https://developer.apple.com/library/ios/documentation/Foundation/Reference/NSFileCoordinator_class/#//apple_ref/c/tdef/NSFileCoordinatorReadingOptions

A URL from a document picker needs to be accessed through a file coordinator. Further more the url needs to be looked in scope:

[url startAccessingSecurityScopedResource];

__block NSData *data

 NSFileCoordinator *coordinator = [[NSFileCoordinator alloc] init];
 NSError *error;
 [coordinator coordinateReadingItemAtURL:url options:0 error:&error byAccessor:^(NSURL *newURL) {
    data = [NSData dataWithContentsOfURL:url];
 }];

 [url stopAccessingSecurityScopedResource];

More from the Apple documentation

The problem was that actually Page documents (*.pages) are not files, but folders. So when I have tried to get NSData from folders path it returns nil.

Default Mail.app attaches documents as zip archives.

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM