iPadアプリ作成日誌: PDF関連APIのバグについて
2010.05.11
以前にもここで少し触れたiPhone OSのPDF関連APIのバグについての詳しい情報が知りたいという連絡がTwitter経由で入ったが、140文字制限でするのもなんなので、具体的にバグレポートを書いてみる。
iPhone OS 上でPDFファイルを表示する場合、まずは CGPDFDocumentCreateWithURL でドキュメントを開く必要がある。CloudReadersの場合はこんな感じだ。
NSURL* url = [NSURL fileURLWithPath:path];
CGPDFDocumentRef doc = CGPDFDocumentCreateWithURL((CFURLRef)url);
count = CGPDFDocumentGetNumberOfPages(doc);
特定のページを表示(=描画)する際には、CGPDFDocumentGetPage でページハンドルを取得し、CGContextDrawPDFPage で描画する。
CGPDFPageRef page = CGPDFDocumentGetPage(doc, i); くせ者はこの CPDFDocumentGetPage。すべてベクター(文字も含む)で書かれたPDFドキュメントの場合、何の問題もないのだが、スキャナーで作ったPDFの場合、大量のメモリーを消費するのだ(手持ちのサンプルだと1ページあたり26MB!)。
CGContextDrawPDFPage(context, page);
それも一時的なものであれば良いのだが、なぜか次のページを描画してもそのメモリは解放されず、そのまま数ページ進むとメモリ不足でアプリが落ちてしまう。
以前、Appleのフォーラムで何人かの人がこの問題を指摘したところ、そのメモリーは CGPDFDocumentRelease を呼べば解放されるので、メモリーリークではなく「高速化のための単なるキャッシュ」という返事がAppleの担当者から返って来た。その人に言わせると、「メモリを節約したいのであれば、「1ページ描画するごとにドキュメントを開いて閉じれば良い」ということ。
私から見れば、これはメモリがふんだんにあるOSXのコードをそのままiPhone OSに持って行ったために生じた不具合である。3〜4ページ描画しただけでアプリが落ちてしまうのだから、十分にバグと呼べると思う。
これが原因で、iPhone/iPad向けのPDFリーダーは、画像ばかりのPDFファイルを開くとメモリ不足で落ちたり、妙に遅くなったりするのだ。CloudReadersの場合、まずはスピード優先で走り、メモリ不足が生じた時点で「Safe Mode」に移行するという綱渡り的なコーディングでしのいでいる。1.04から落ちにくくなったのはそのため。
Comments