Не секрет, что PDF документ в приложении можно показать в UIWebView. Но, что делать, если вас не устраивает то, как UIWebView отображает документ? Может быть вы хотите сделать свой механизм перехода по страницам?

В iOS PDF можно отобразить через CoreGraphics. При использовании этого подхода каждая страница рисуется отдельно. Т.е. если нужно сделать переход по страницам в документе — нужно будет все делать вручную.

Итак, предположим, что у нас в Bundle приложения лежит PDF-файл idevby.pdf. Как его отобразить? Создадим класс PDFView, который будет это отображать:

@interface PDFView : UIView
@end
В классе перекроем метод drawRect::

- (void)drawRect:(CGRect)rect
{
    // путь до документа
    CFURLRef url = (CFURLRef)[NSURL fileURLWithPath:[[NSBundle mainBundle] pathForResource:@"idevby" ofType:@"pdf"]];

    // открываем документ
    CGPDFDocumentRef pdfDocument = CGPDFDocumentCreateWithURL(url);
    // если в документе нет страниц - ничего отображать не нужно
    if ( CGPDFDocumentGetNumberOfPages(pdfDocument) > 0 )
    {
        // получим первую страницу (страницы нумеруются с первой)
        CGPDFPageRef pdfPage = CGPDFDocumentGetPage(pdfDocument, 1);
        // получим необходимое преобразование
        CGAffineTransform t = CGPDFPageGetDrawingTransform(pdfPage, kCGPDFCropBox, self.bounds, 0, 1);
        CGContextRef context = UIGraphicsGetCurrentContext();
        CGContextSaveGState(context);
        // применим преобразование
        CGContextTranslateCTM(context, 0, self.bounds.size.height);
        CGContextScaleCTM(context, 1, -1);
        CGContextConcatCTM(context, t);
        // отрисуем страницу
        CGContextDrawPDFPage(context, pdfPage);
        CGContextRestoreGState(context);
    }
    // закроем документ
    CGPDFDocumentRelease(pdfDocument);
}
Рассмотрим основные моменты.

При отрисовке PDF-страницы мы сохраняем состояние контекста, а затем восстанавливаем его:
CGContextSaveGState(context);
...
CGContextRestoreGState(context);
Этого можно было бы и не делать, но если вы захотите рисовать что-то после отрисовки PDF-страницы — это необходимо, иначе то, что вы нарисуете может быть искривлено.

Нам необходимо отразить контекст по вертикали, иначе документ будет показан «вверх ногами». Это связано с тем, что в данном случае ось Y направлена снизу вверх.

CGContextTranslateCTM(context, 0, self.bounds.size.height);
CGContextScaleCTM(context, 1, -1);
Ну и самое интересное:

CGAffineTransform t = CGPDFPageGetDrawingTransform(pdfPage, kCGPDFCropBox, self.bounds, 0, 1);
...
CGContextConcatCTM(context, t);

CGContextDrawPDFPage(context, pdfPage);
Функция CGPDFPageGetDrawingTransform возвращает трансформацию для контекста, которую нужно применить, чтобы целиком отобразить заданную область страницы в заданной области view. Трансформацию применяет функция CGContextConcatCTM. Первым аргументом функции CGPDFPageGetDrawingTransform является страница, которую хотим отобразить. Второй аргумент — область документа для отображения. Области определены так:

enum CGPDFBox {
kCGPDFMediaBox = 0,
kCGPDFCropBox = 1,
kCGPDFBleedBox = 2,
kCGPDFTrimBox = 3,
kCGPDFArtBox = 4
};
Третий аргумент — область на view, где будет отображена страница, в данном случае мы используем всю область. Четвертый аргумент — угол вращения в градусах, должен быть обязательно кратным 90. Пятый аргумент — сохранять ли пропорции сторон при отрисовке.

Конечно-же, этот способ более трудоемкий, чем способ с использованием UIWebView. Но, используя такой подход, мы можем получить больше возможностей для кастомизации отображения PDF. Есть и минус данного подхода — если в документе есть ссылки — они не будут активными и необходимо будет применять дополнительные средства.

На этом все, спасибо за внимание. Загрузить исходный код можно отсюда.