3

iPad用のpdfリーダーアプリがあり、スクロールビューを使用して各ページを表示しています。ページを表示したままにし、ページの両側に 1 ページを表示します。縦向きビューと横向きビューに別々のビューがあります。縦表示では 1 ページが表示され、横表示では 2 ページが表示されます。

iPad の向きが変わると、古い向きのビューをアンロードし、新しい向きのビューをロードします。つまり、縦向きのビューで横向きに変更すると、アプリは縦向きのビューをアンロードし、横向きのビューをロードします。PDFが大きい場合を除いて、これはすべてうまく機能します。

PDF は tiledlayers を使用して描画されます。大きな PDF で向きを変更すると、アプリがクラッシュします。タイルがすべて描画される前に向きが変更された場合にのみ、アプリがクラッシュします。私の推測では、アンロードされたタイルよりもビューにタイルを描画しようとしているため、クラッシュしていると思われます。ビューをアンロードするときにタイルの描画を停止する方法はありますか?

4

2 に答える 2

5

CALayer のデリゲートを nil に設定してから、スーパービューから削除する必要があります。これによりレンダリングが停止します。その後、安全に解放できます。

- (void)stopTiledRenderingAndRemoveFromSuperlayer; {
    ((CATiledLayer *)[self layer]).delegate = nil;    
    [self removeFromSuperview];
    [self.layer removeFromSuperlayer];
}

また、必ずメイン スレッドから呼び出してください。そうしないと、恐ろしいバグが発生します。

于 2011-08-01T23:44:30.963 に答える
3

私は逆アセンブルを確認していませんが、少し異なるソリューションを使用しています。CATiledLayer.contentプロパティをブロックに設定し、nilキューに入れられたすべてのレンダー ブロックを強制的に完了させます。これは安全にバックグラウンド スレッドにUIViewキックオフできます。その後、解放するとメイン スレッドにキックバックして、ビューとレイヤーのロックを解除できます。

メイン スレッドをブロックすることなく、レンダリングを安全に停止するのに十分な時間、所有しているビューUIViewController deallocを維持する実装の例を次に示します。CATiledLayer

- (void)dealloc
{
    // This works around a bug where the CATiledLayer background drawing 
    // delegate may still have dispatched blocks awaiting rendering after
    // the view hierarchy is dead, causing a message to a zombie object.
    // We'll hold on to tiledView, flush the dispatch queue, 
    // then let go of fastViewer.
    MyTiledView *tiledView = self.tiledView;
    if(tiledView) {
        dispatch_background(^{
            // This blocks while CATiledLayer flushes out its queued render blocks.
            tiledView.layer.contents = nil;

            dispatch_after(dispatch_time(DISPATCH_TIME_NOW, (int64_t)(0.01 * NSEC_PER_SEC)), dispatch_get_main_queue(), ^{
                // Make sure tiledView survives until now.
                tiledView.layer.delegate = nil;
            });
        });
    }
}

これは推測ですが、一部の Apple のフレームワーク/クラス (StoreKit、CATiledLayer、UIGestureRecognizer) は@property (weak) id delegate実装があると主張していますが、デリゲートを適切に処理していませんweak。いくつかの逆アセンブルを見ると、彼らは明らかに人種に縛られif != nilたチェックを行ってから、弱いプロパティに直接触れています。適切な方法は、 a を宣言すること__strong Type *delegate = self.delegateです。これは成功し、存続が保証された強力な参照を与えるか、または になりますnilが、ゾンビ オブジェクトへの参照を与えることはありません (私の推測では、フレームワーク コードはアップグレードされていません) ARCへ)。

内部CATiledLayer的には、バックグラウンド レンダリングを行うディスパッチ キューを作成し、安全でない方法でデリゲート プロパティに触れているように見えるか、ローカル参照を取得しても強力なものにはしていないように見えます。いずれにせよ、デリゲートの割り当てが解除された場合、ディスパッチされたレンダー ブロックはゾンビ オブジェクトに喜んでメッセージを送信します。デリゲートをクリアするだけでは不十分です。クラッシュの数は減りますが、安全に排除することはできません。

を設定するcontent = nilと、dispatch_wait が実行され、既存のキューに入れられたすべてのレンダー ブロックが完了するまでブロックされます。が安全であることを確認するために、メイン スレッドに戻りdeallocます。

誰かが改善のための提案を持っているなら、私に知らせてください。

于 2014-12-01T20:10:32.190 に答える