2013年8月16日金曜日

PDFサムネイル表示改良版



PDFサムネイル表示の例では全ページのサムネイルを作り終えるまで応答しなくなる、メモリ不足になっても回復不能でアプリが落ちるという問題があります。その改善策の例です。

@implementation WebViewWithThumnails

//WebViewWithThumnailsではプレイスホルダーとなるThumbnailViewの配置だけ
//行い、サムネイルイメージはセットしない。
- (void)addThumbnailsWithData:(NSData *)pdfData
{
    //画面下にUIScrollViewを追加
    _thumbnailScrollView =
        [[ThumbnailScrollView alloc] initWithWebView:self height:80];
    [_thumbnailScrollView addThumbnailViews:pdfData];
    //この行を削除。
    //[_thumbnailScrollView setPdfThumbnailImage:pdfData];
}

@implementation ThumbnailScrollView

//layoutSubviewsをオーバライドし、表示領域内にあるThumbnailViewに
//サムネイルイメージをセットする。
- (void)layoutSubviews
{
    float x1 = self.contentOffset.x;
    float x2 = x1 + self.frame.size.width;
    NSMutableArray *views = [NSMutableArray arrayWithCapacity:16];
    for(ThumbnailImageView *v in self.subviews) {
        if ([v isMemberOfClass:[ThumbnailImageView class]]) {
            if (v.frame.origin.x >= x1 - v.frame.size.width && v.frame.origin.x <= x2
                && v.subviews.count < 2) {
                [views addObject:v];
            }
        }
    }
    //すぐにサムネイルを作らず、performSelector:withObject:afterDelay:でキュー
    //に入れる。cancelPreviousPerformRequestsWithTarget:を呼ぶことで、
    //layoutSubviewsが続けて呼ばれた場合に最後のものだけが実行される。
    if (views.count > 0) {
        [NSObject cancelPreviousPerformRequestsWithTarget:self];
        [self performSelector:@selector(setImagesWithViewArray:) withObject:views afterDelay:0.1];
    }
    [super layoutSubviews];
}

- (void)setImagesWithViewArray:(NSArray *)views
{
    //残りメモリが不足していたらメモリ空き容量を増やす。
    if (_memMonitor.freeMemory < 50000000) {
        [self removeThumbnailImages];
        //十分メモリが空いたかわからないのでreturn。
        return;
    }
    //表示領域内のサムネイル画像を表示する。
    for(ThumbnailImageView *v in views) {
        CGPDFPageRef page = CGPDFDocumentGetPage(_pdf, v.pageNum);
        [v setImageWithPdfPage:page];
    }
}

//この例では既に作成されているサムネイル画像を全て解放する。
- (void)removeThumbnailImages
{
    for(UIView *v in self.subviews) {
        if ([v isMemberOfClass:[ThumbnailImageView class]]) {
            [(ThumbnailImageView *)v removeThumbnailImage];
        }
    }
}

0 件のコメント: