0

假設您有一個類似於NSSlider的自定義控件,但支持選擇一系列值,而不是單個值。屬性的明顯選擇是minValue,maxValue,leftValue,rightValue,或者您想要命名它們。
您可能還想確保leftValue和rightValue總是位於minValue和maxValue之間。 minValue和maxValue相同。您不希望它們潛在地使現有的leftValue和rightValue失效,如我們所說的 - 將maxValue設置爲低於當前rightValue的值。如何確保適合我的NSSlider自定義控件的正確KVO行爲?

迄今爲止非常直截了當。

但是,如果確保正確的KVO可訪問性/容錯性,您會做什麼?您無法確保KVO以正確的順序設置屬性(即首先設置最小值和最大值以及其他值)。

我碰巧擁有這樣一個UI元素,並且根本無法弄清楚熱度如何在沒有打開虛假設置值的情況下運行。

自定義控件意味着綁定到模型對象。 如果我現在用(min:0.00 max:42.00 left:14.00 right:28.00)創建一個這樣的模型我最後在自定義控件(min:0.00 max:42.00 left:1.00 right :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]; 
    } 

它的時候像這樣的,當你想蘋果已經開闢了可可的來源。或者至少有一些控制更深入的檢查。

您將如何實施這樣的控制?

或者更一般的:在遵守KVO的同時實現具有交叉相關屬性的類的最佳實踐是什麼?

+0

「** it **先調用leftValue和rightValue」是什麼意思?它是什麼」? – TechZen 2010-06-30 14:03:22

+0

TechZen,視圖的值綁定到的任何模型對象。 (當然,技術性「它」將是蘋果的內部綁定機制。) 是什麼導致問題是KVO方法調用順序的不可預測性。 – Regexident 2010-07-05 15:09:46

回答

1

哇。這是一個棘手的問題。正如您已經確定的那樣,您無法確保以任何特定順序發送KVO消息。

這裏有一個想法:在你的setLeftValue:setRightValue:存取,而不是微調的價值,爲什麼不只是存儲則傳遞的值,然後修剪上獲得的價值。

例如:

- (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

此外,對於您正在編寫的代碼,MINMAX預處理器宏將爲您節省大量的工作量。

+0

可能不是最佳做法,但絕對是解決我的問題的方法(至少目前爲止)。非常感謝! 但setMaxValue:和setMinValue:應該可能直接影響leftValue和rightValue的值。至少這就是蘋果的實施似乎正在做的事情。 證明:將NSSlider的值設置爲10,然後將最大值設置爲5,然後將其設置爲15,使NSSlider在下一次請求其值時返回5。 – Regexident 2010-07-05 15:13:46

0

不完全確定我明白你想要做什麼,但你的問題與KVO無關。

第一次setLeftValue:被稱爲後準備將其設置爲14.0,您將看到的變量值以下的parethesis:

- (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設置器,因此它們對此代碼沒有影響。

相關問題