0

NSSlider に似たカスタム コントロールがあるとしますが、単一の値ではなく、値の範囲の選択をサポートしているとします。プロパティの明らかな選択は、minValue、maxValue、leftValue、rightValue、または任意の名前です。
また、おそらく leftValue と rightValue が常に minValue と maxValue の間にあることを確認することもできます。minValue と maxValue についても同じです。たとえば、maxValue を現在の rightValue よりも低い値に設定するなどして、既存の leftValue と rightValue を潜在的に無効にすることは望ましくありません。

これまでのところかなり簡単です。

ただし、適切な KVO アクセシビリティ/コンプライアンスを確保する場合はどうしますか? KVO が適切な順序でプロパティを設定することを保証することはできません (つまり、最初に最小制限と最大制限を設定し、次に他の値を設定します)。

私はたまたまそのようなUI要素を持っていて、誤って設定された値のドアを開けずにこれを実行するために熱く理解することはできません.

カスタム コントロールは、モデル オブジェクトにバインドされることを意図しています。このようなモデルを値(最小: 0.00 最大: 42.00 左: 14.00 右: 28.00)で作成すると、カスタム コントロールで次のように設定されます(最小: 0.00 最大: 42.00 左: 1.00 右: 1.00)。

これは、minValue と maxValue を最初に呼び出す代わりに、leftValue と rightValue を最初に呼び出し、両方の値が 1.0 (デフォルトの maxValue) になるためです。(その後、maxValue が適切な値に設定されます。)

//[self prepare] gets called by both, [self initWithCoder:] and [self initWithFrame:]
- (void)prepare
{
    minValue = 0.0;
    maxValue = 1.0;
    leftValue = 0.0;
    rightValue = 1.0;       
}

- (void)setMinValue:(double)aMinValue
{
    if (aMinValue < maxValue && aMinValue < leftValue) {
        minValue = aMinValue;
        [self propagateValue:[NSNumber numberWithDouble:minValue] forBinding:@"minValue"];
        [self setNeedsDisplay:YES];
    }   
}

- (void)setMaxValue:(double)aMaxValue
{
    if (aMaxValue > minValue && aMaxValue > rightValue) {
        maxValue = aMaxValue;
        [self propagateValue:[NSNumber numberWithDouble:maxValue] forBinding:@"maxValue"];
        [self setNeedsDisplay:YES];
    }
}

- (void)setLeftValue:(double)aLeftValue
{
    double newValue = leftValue;
    if (aLeftValue < minValue) {
        newValue = minValue;
    } else if (aLeftValue > rightValue) {
        newValue = rightValue;
    } else {
        newValue = aLeftValue;
    }
    if (newValue != leftValue) {
        leftValue = newValue;
        [self propagateValue:[NSNumber numberWithDouble:leftValue] forBinding:@"leftValue"];
        [self setNeedsDisplay:YES];
    }
}

- (void)setRightValue:(double)aRightValue
{
    double newValue = leftValue;
    if (aRightValue > maxValue) {
        newValue = maxValue;
    } else if (aRightValue < leftValue) {
        newValue = leftValue;
    } else {
        newValue = aRightValue;
    }
    if (newValue != rightValue) {
        rightValue = newValue;
        [self propagateValue:[NSNumber numberWithDouble:rightValue] forBinding:@"rightValue"];
        [self setNeedsDisplay:YES];
    }

Apple が Cocoa のソースを公開していればよかったのにと思うのは、このようなときです。または、より詳細な検査のための少なくともいくつかのコントロール。

そのような制御をどのように実装しますか?

または、より一般的な: KVO に準拠しながら、相互に依存するプロパティを持つクラスを実装するためのベスト プラクティスは何ですか?

4

2 に答える 2

1

わお。これは難しい問題です。既に特定したように、KVO メッセージが特定の順序で送信されるようにするためにできることは何もありません。

ここに 1 つの考えがあります。あなたのsetLeftValue:andsetRightValue:アクセサーでは、値をトリミングする代わりに、渡された値を保存してから、アクセス時に値をトリミングしないでください。

例えば:

- (void)setLeftValue:(double)value {
    leftValue = value;
    [self propagateValue:[NSNumber numberWithDouble:self.leftValue] forBinding:@"leftValue"]; // Note the use of the accessor here
    [self setNeedsDisplay:YES];
}

- (double)leftValue {
    return MAX(self.minValue, MIN(self.maxValue, leftValue));
}

このように、minValuemaxValueが設定されるleftValuerightValue、正しい値が表示されます。また、カスタム アクセサーを使用することで、制約が確実にminValue <= leftValue/rightValue <= maxValue保持されるようにすることができます。

また、作成中のコードについては、MINおよびMAXプリプロセッサ マクロを使用すると、多くの労力を節約できます。

于 2010-06-30T14:37:55.390 に答える
0

あなたが何をしようとしているのか正確にはわかりませんが、あなたの問題は KVO とは何の関係もありません。

14.0 に設定するために準備した後に初めてsetLeftValue:呼び出されると、次のように括弧内に変数の値が表示されます。

- (void)setLeftValue:(double)aLeftValue(14.0)
{
    double newValue = leftValue(0.0);
    if (aLeftValue(14.0) < minValue(0.0)) {
        newValue = minValue(0.0);
    } else if (aLeftValue(14.0) > rightValue(1.0)) { // always evaluates true for all aleftValue>1
        newValue = rightValue(1.0); // now newValue==1.0
    } else {
        newValue = aLeftValue(14.0);
    }
    if (newValue(1.0) != leftValue(0.0)) {
        leftValue = newValue(1.0); // now leftvalue==1.0
        [self propagateValue:[NSNumber numberWithDouble:leftValue] forBinding:@"leftValue"];
        [self setNeedsDisplay:YES];
    }
}

すべての aLeftvalues>1場合、このコードは常に設定されleftValue==1.0ます。

minValue および maxValue セッターのいずれも呼び出さないため、このコードには影響しません。

于 2010-06-30T14:37:11.553 に答える