Apple Developer Connection
高度な検索
Member Login ログイン | ご入会 ADC連絡先

カスタムビュークラスにおける-needsToDrawRect:の不正な動作の回避

OS X 10.3 Pantherで初めて導入された、NSViewの簡易メソッドである-needsToDrawRect:は、いくつかの状況では間違ってNOを返します。その結果、コンテンツのうちどの部分を描画すべきかを決定するのに-needsToDrawRect:を使用しているカスタムビュークラスでは、描画が不完全なものになる可能性があります。

このテクニカルノートでは、Mac OS X 10.4 Tigerでは修正済みの、間違った動作を回避する方法について説明します。





重要: NSView-needsToDrawRect:は、Mac OSX 10.4 Tigerで修正されています。以下に示す対処方法は、10.4以降で動作するソフトウェアには必要ありません。Mac OS X 10.3 Pantherをターゲットにする必要のあるデベロッパには依然として必要です。

背景

Mac OS X 10.3では、Cocoaビュー用に最適化した描画モデルが導入されました。このモデルは新しいNSViewメソッド-getRectsBeingDrawn:count:-needsToDrawRect:によってサポートされており、ビューの描画をコンテンツ領域において更新する必要のある部分に正確に限定することができます。これら新しいメソッドの使用については、『View Programming Guide for Cocoa』の「Constraining Drawing to Improve Performance」で詳しく説明されています。

-needsToDrawRect:メソッドは、ビューの-drawRect:の実装が、コンテンツ領域内の特定のオブジェクトを描画する必要があるかどうかを調べるための便利な手段として提供されています。-needsToDrawRect:にオブジェクトの境界矩形を渡すと、この矩形が再表示を必要とするビューの一部と重なっている場合はYESが返されます。

先頭に戻る

問題点

効率化のために、 NSView-needsToDrawRect:の実装はまず、渡された矩形が、描画する領域の境界ボックスと重なるかどうかをテストします。場合によっては(ほとんどはビューにテキストを描画する場合)、この境界矩形の計算に間違いが生じ、その結果-needsToDrawRect:が間違ってNOを返します。この間違った動作によって、-needsToDrawRect:の結果に応じて描画を行う処理が実行されなくなります。

先頭に戻る

-needsToDrawRect:をオーバーライドして正しく実行

この問題を回避して意図したとおりに動作させるには、-needsToDrawRect:を使用するカスタムビュークラスにおいて、-needsToDrawRect:をオーバーライドします。

ビューが一度に多数の矩形を描画するよう要求されることがめったになく、そのコンテンツを描画するのがとくに複雑または高価でない場合は、次のような-needsToDrawRect:の再実装で十分です。

リスト1:シンプルな-needsToDrawRect:の差し替え版

- (BOOL)needsToDrawRect:(NSRect)rect
{
    const NSRect *rectList;
    int count;
    int i;

    [self getRectsBeingDrawn:&rectList count:&count];
    for (i = 0; i < count; i++) {
        if (NSIntersectsRect(rect, rectList[i])) {
            return YES;
        }
    }
    return NO;
}

上記のアプローチには、 -needsToDrawRect:を呼び出すコードを変更する必要がないという利点があります。

通常、一度に描画する矩形が多数あるビューの場合にパフォーマンスを改善するには、このメソッドでrectListの境界矩形の外側にあるオブジェクトを迅速に拒否する、別のメソッドを定義して使用することが考えられます。-needsToDrawRect:の代わりに次のメソッドを呼び出し、rectListBoundsパラメータとして-drawRect:の矩形パラメータを渡します。

リスト2:より最適化された-needsToDrawRect:の差し替え版

- (BOOL)needsToDrawRect:(NSRect)rect rectListBounds:(NSRect)rectListBounds
{
    const NSRect *rectList;
    int count;
    int i;

    if (!NSIntersectsRect(rect, rectListBounds)) {
        return NO;
    }
    [self getRectsBeingDrawn:&rectList count:&count];
    if (count == 1) {
        return YES;
    } else {
        for (i = 0; i < count; i++) {
            if (NSIntersectsRect(rect, rectList[i])) {
                return YES;
            }
        }
        return NO;
    }
}

先頭に戻る

ドキュメント改訂履歴

日付メモ
2007-01-22Mac OS X 10.4 Tigerの修正を反映するために更新。
2004-02-06NSViewの-needsToDrawRect:メソッドのバグを回避する方法の説明。

掲載日: 2007-01-22




Did this document help you?
Yes: Tell us what works for you.

It’s good, but: Report typos, inaccuracies, and so forth.

It wasn’t helpful: Tell us what would have helped.