Question

I'm currently working on a Cocoa application that works with PDFs, and am using Apple's PDFKit to do the work. Saving the PDF is proving a problem, as I'd like to show a progress bar while that's happening, which doesn't seem to be possible using the standard writeToURL: method. So, I went and used Grand Central Dispatch instead.

The problem with this is that the dataRepresentation method used to get the NSData to write is terribly slow in converting any PDF larger than ~3MB to NSData, and so the progress bar stalls for a few seconds while my program is waiting for the data, which seems to make the users think the program has stalled completely. And I don't really want them thinking that.

My question is, is there anything I can do to either speed up the dataRepresentation method, or report its progress to the user?

Here's the Grand Central Dispatch code I ended up writing:

NSData *pdf = [doc dataRepresentation]; // R-e-a-l-l-y S-l-o-w

dispatch_queue_t queue = dispatch_get_current_queue();
dispatch_data_t dat = dispatch_data_create([pdf bytes], [pdf length], queue, DISPATCH_DATA_DESTRUCTOR_DEFAULT);

__block dispatch_io_t channel =
dispatch_io_create_with_path(DISPATCH_IO_STREAM,
                             [path UTF8String],     // Convert to C-string
                             O_WRONLY,              // Open for writing
                             0,                     // No extra flags
                             queue,
                             ^(int error){
                                 // Cleanup code for normal channel operation.
                                 // Assumes that dispatch_io_close was called elsewhere.
                                 if (error == 0) {
                                     dispatch_release(channel);
                                     channel = NULL;
                                 }
                             });
// The next two lines make sure that the block in dispatch_io_write
// gets called about 60 times, so that it can update the progress bar.
dispatch_io_set_low_water(channel,[pdf length]/60);
dispatch_io_set_high_water(channel,[pdf length]/60);

dispatch_io_write(channel,
                  0,
                  dat,
                  queue,
                  ^(bool done, dispatch_data_t data, int error) {
                      if (data) {
                          // Increment progress bar
                      }
                      if (error) {
                          // Handle errors
                      }
                      if (done) {
                          dispatch_io_close(channel, NULL);
                      }
                  });
dispatch_release(dat);
dispatch_release(queue);
Was it helpful?

Solution

Use the PDFDocumentDidBeginPageWriteNotification and PDFDocumentDidEndPageWriteNotification notifications, which are sent during -writeToURL:. The notifications tell you what page is processing, which you can compare to the total number of pages in the document to show progress.

Licensed under: CC-BY-SA with attribution
Not affiliated with StackOverflow
scroll top