13
votes

I am trying to preview pdf file in QLPreviewController and using the below code. It works fine on iOS7 and for other type of files (JPG/PNG) on iOS8 as well but when I try to open pdf it shows blank page instead content on iOS8. Its weird that it still shows name of pdf in title view.

Code:

QLPreviewController *previewer = [[QLPreviewController alloc] init];
previewer.dataSource = self;
previewer.currentPreviewItemIndex = 0;
[self presentViewController:previewer animated:NO completion:nil];

And QLPreviewControllerDataSource methods:

- (NSInteger)numberOfPreviewItemsInPreviewController:(QLPreviewController *)controller {
    return 1;
}

- (id<QLPreviewItem>)previewController:(QLPreviewController *)controller previewItemAtIndex:(NSInteger)index {
    return [NSURL fileURLWithPath:self.pdfUrl];
}
9
Are you putting the QLPreviewController in a UINavigationController?CrimsonChris

9 Answers

5
votes
5
votes

There seems to be a bug when placing a QLPreviewController inside of a UINavigationController. It just shows up as a black view even if the document is loaded.

UINavigationController *navController = [[UINavigationController alloc] initWithRootViewController:previewController];
[self presentViewController:navController animated:YES completion:nil];

The solution is to not use a navigation controller. QLPreviewController overrides the navigation bar anyways.

[self presentViewController:previewController animated:YES completion:nil];
5
votes

There are probably two things here involved.

For those implementing QLPreviewController in a UINavigationController, there's probably an issue there.

For those still having the issue without the UINavigationController, read on.

In iOS 8.0, file path to Data has changed. So if you are using older bundle path to access your resources you might have an issue.

We did investigate this and it turns out:

  • that you need to pay close attention to the way you get the full path to the documents directory
  • that QLPreviewController CAN'T display a file in a subfolder of this Documents directory if you did not create it.

For instance, our problem was that our PDF file was opened from an outside application using the traditional "Open In".

This was resulting in the file being copied to the Inbox directory inside the Documents directory of the App.

The file IS displayed correctly on the simulator, regardless of the QLPreviewController being embedded in a UINavigationController or not.

The file IS NOT displayed correctly on a real iOS Device.

Before sending the file URL to the QLPReviewController, we did copy the file to the root of the Documents directory, passing this new URL to the QLPreviewController. And then bingo, it worked.

So in order to stop this issue, make sure you copy the resource in a directory you actually own. Until someone can explain how to play around with the rights on the Inbox (probably shared) directory.

4
votes

I just recently encountered a blank page again and I have found the reason to be that I did something like

previewController.dataSource = [[MyDataSource alloc] initWithSomething];

Since the QLPreviewController holds its dataSource as a weak variable, the data source immediately vanishes.

Keeping a strong reference to the dataSource helped.

2
votes

Use this code if you in desperate need to use QLPreviewController embedded in UINavigationController:

#import <Quicklook/QLPreviewController.h>

...

QLPreviewController *pc = [[QLPreviewController alloc] init];
pc.delegate = self;
pc.dataSource = self;

UINavigationController *nc = [[UINavigationController alloc] init];
nc.view.backgroundColor = [UIColor whiteColor];
nc.navigationBarHidden = YES;

[self presentViewController:nc animated:YES completion:nil];
[nc pushViewController:pc animated:NO];
1
votes

I had the same problem, and I needed to call reloadData() after I set the dataSource to a new value.

0
votes

Works fine with me on iOS8.1

Make sure you download the doc file into a proper file path

 NSArray *paths = NSSearchPathForDirectoriesInDomains(NSCachesDirectory, NSUserDomainMask, YES);
NSString *cachePath = [paths objectAtIndex:0];

urlString = [urlString stringByReplacingOccurrencesOfString:@"/" withString:@""];
 filePath = [cachePath stringByAppendingPathComponent:urlString];
BOOL fileExists = [[NSFileManager defaultManager] fileExistsAtPath:filePath];
if (fileExists == NO) {
    NSData *pdfData = [[NSData alloc] initWithContentsOfURL:[NSURL URLWithString:mainPadfLink]];
    [pdfData writeToFile:filePath atomically:YES];

}

and load it into your QLPreviewControl

- (id <QLPreviewItem>)previewController:(QLPreviewController *)controller previewItemAtIndex:(NSInteger)index
{
    return [NSURL fileURLWithPath:filePath];
}

And make sure that you open the QLPreviewControl with presentViewController don't push it into your navigation controller

0
votes

For iOS 9.2: In Monotouch.ios,

use

var url = NSUrl.FromFilename(NSBundle.MainBundle.PathForResource ("pdf.pdf", null)); 

instead of

var url = NSUrl.FromFilename("pdf.pdf");

It will work for all files. (jpg,png,pdf,etc)

0
votes

I had a problem (and still have) with presenting documents from bundle (xCode 9.2, iOS 11). It only displays images. For other documents (pdf, key, rtf, pages, docx, txt ...) it only shows the name and not the content. I'm presenting controller modally and the datasource is implemented like this:

func numberOfPreviewItems(in controller: QLPreviewController) -> Int {
    return 1
}
func previewController(_ controller: QLPreviewController, previewItemAt index: Int) -> QLPreviewItem {

    let url = Bundle.main.url(forResource: "test", withExtension: "pdf")!


    if QLPreviewController.canPreview(url as NSURL) {
        print("This file can be previewed.")
    } else {
        print("This file can not be previewed.")

    }
     return url as NSURL
}

Of course, it shows that file CAN be previewed, but it doesn't preview it. Currently I'm solving this by copying file to documents directory and passing that url to datasource.