32474

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.

Answer1:

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

Answer2:

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

Answer3:

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.

Recommend

  • Error while uploading file to Amazon S3 bucket
  • “Insert disk into Drive D” blocks Haskell from starting
  • Android Galaxy S Phone - ADB Debug Bridge Trouble on Mac OSX
  • Lotus Notes - open a file from Action Button
  • How to grant permission for a group of users instead of whole organization using /adminconsent endpo
  • Animation: Timer vs Idle
  • Prevent users from voting multiple times in Rails
  • sequel trying to use postgresql instead of postgres as adapters
  • Boot EBS volume from Bamboo instance
  • Python Pandas global vs passed variable
  • Get data file from microphone in windows phone 7
  • Unexpected end of JSON input Angular 2(4) http get request
  • How to read a certificate from a USB token in C#
  • Client-Side: Accessing Windows Azure Drive?
  • How to get ID of changed file on Google Drive
  • WordPress > setting permalink option via script buggy?
  • Do I need to seed any random number generator before using EVP_PKEY_keygen of OpenSSL?
  • JqueryMobile Popup menu is not working
  • How can I enlarge video fullscreen without the affected interface project in as3?
  • Repeat a vertical line on every page in Report Builder / SSRS
  • Why value captured by reference in lambda is broken? [duplicate]
  • Display issues when we change from one jquery mobile page to another in firefox
  • Splitting given String into two variables - php
  • NetLogo BehaviorSpace - Measure runs using reporters
  • Is my CUDA kernel really runs on device or is being mistekenly executed by host in emulation?
  • Different response to non-authenticated users and AJAX calls
  • Arrow is showed instead of the material design version hamburger icon. Why doesn't syncState in
  • Build own AppleScript numerical error handling
  • Do create extension work in single-user mode in postgres?
  • R: gsub and capture
  • jqPlot EnhancedLegendRenderer plugin does not toggle series for Pie charts
  • How do I rollback to a specific git commit
  • Is there a mandatory requirement to switch app.yaml?
  • Data Validation Drop Down Box Arrow Disappearing
  • Comma separated Values
  • Why joiner is not used after Sequence generator or Update statergy
  • Busy indicator not showing up in wpf window [duplicate]
  • Recursive/Hierarchical Query Using Postgres
  • UserPrincipal.Current returns apppool on IIS
  • How to load view controller without button in storyboard?