2012-02-13 3 views
6

私のモデルクラスは主に合成されたセッター/ゲッターメソッドで実装されています。すべてがうまくユーザーインターフェイスに接続されていました。後でtypeを変更するとminAmaxAが変更される可能性があるので、1つのプロパティを変更すると他のプロパティが変更される可能性があることに気が付いたので、typeプロパティのsetter/getterメソッドを手動で書きました。コードは次のとおりです。自分のKVCセッター/ゲッターメソッドを実装するときにキャッチされない例外が発生するのはなぜですか?

QBElementType

@interface QBElementType : NSObject 
    @property NSRange minRange; 
    @property NSRange maxRange; 
@end 

@implementation QBElementType 
    @synthesize minRange; 
    @synthesize maxRange; 
@end 

QBElement

@interface QBElement : QBElementType{ 
    QBElementType *_type; 
} 
    @property (weak) QBElementType *type; 
    @property NSUInteger minA; 
    @property NSUInteger maxA; 
@end 


@implementation QBElement 
    @synthesize minA = _minA; 
    @synthesize maxA = _maxA; 

- (QBElementType*)type 
{ 
    return _type; 
} 
- (void)setType:(QBElementType*)newType 
{ 
    [self willChangeValueForKey:@"type"]; 
    _type = newType; // no need to bother with retain/release due to ARC. 
    [self didChangeValueForKey:@"type"]; 

    /* Having the following 4 lines commented out or not changes nothing to the error 
    if (!NSLocationInRange(_minA, newType.minRange)) 
     self.minA = newType.minRange.location; 
    if (!NSLocationInRange(_maxA, newType.maxRange)) 
     self.maxA = newType.maxRange.location; 
    */ 
} 
@end 

をQUESTION

:私は要素の種類を変更するたびにそれ以来、私は キャッチされない例外を取得

からキーパス 「type.minRange」のためのオブザーバー< NSTableBinder ...>のため更新できません< QBElement ...>、 キー「タイプ」の値が適切なKVOなしに変更されたため、最も可能性が高いです通知 が送信されています。 QBElementクラスのKVO準拠を確認します。

KVO-Complianceには何かがありますか?このエラーが発生するのはなぜですか?

答えて

3

セッターの名前が正しく設定されているため、-willChangeValueForKey:-didChangeValueForKey:を明示的に呼び出す必要はありません。それらの呼び出しは、KVC/KVOの機械の魔法によって自動的に追加されます。問題は、効果的に2度呼び出されているということかもしれません。

@interface QBElement : QBElementType{ 
    QBElementType *_type; 
} 
    @property (weak) QBElementType *type; 
    @property (readonly) NSUInteger minA; 
    @property (readonly) NSUInteger maxA; 
@end 

@implementation QBElement 

+ (NSSet *)keyPathsForValuesAffectingValueForKey:(NSString *)key 
{ 
    NSSet *keyPaths = [super keyPathsForValuesAffectingValueForKey:key]; 

    if ([key isEqualToString:@"minA"] || 
     [key isEqualToString:@"maxA"]) { 
     keyPaths = [keyPaths setByAddingObject:@"type"]; 
    } 

    return keyPaths; 
} 

@synthesize type; 

- (NSUInteger)minA 
{ 
    return self.type.minRange.location; 
} 

- (NSUInteger)maxA 
{ 
    return self.type.maxRange.location; 
} 

@end 
+0

私は 'willChangeValueForKey:'と 'didChange ....'を使わずにアプリを実行しようとしましたが、ユーザーインターフェースは決して変更を通知されませんでした! (サイドノート:minAはそれ自体の変数ですが、この質問のコードを簡略化したため、このようには表示されないかもしれません) –

+0

その場合、何か間違っています。あなたは本当にそのようなセッターで 'willChange ...'と 'didChange ...'を呼び出す必要はありません。 「minA」がそれ自体の変数であるとして理解され、その場合、私の提案は機能しません。ただし、簡略化が変更されたり問題が取り除かれた場合に備えて、完全なコードを投稿してください。 –

2

手動設定ツールを実装しても、必ず手動KVO通知を実装する必要はありません。あなたがセッターを経由せずにプロパティのための裏地のivarを更新している場合は、それらを絶対に必要とするだけです。 KVOは自動的にあなたのセッターを "実際の"セッターが呼び出される前と後にwill/didChangeメソッドを呼び出すバージョンに置き換えます。設定者に自分自身を呼び出す場合は、typeキーにNOを返すように、+automaticallyNotifiesObserversForKey:メソッドをオーバーライドする必要があります。

[self didChangeValueForKey:@"type"]を呼び出さずに、[self willChangeValueForKey:@"type"]を2度続けて(KVOの「マジック」を1回、手動で1回)呼び出すと、KVOのマシンでエラーが発生すると想定します。

0

:それはminAmaxAが単純型から導出されているように見えることから、あなたは読み取り専用それらを作ると自動的にミナとMAXAは、任意の時間にtype変更を変更したオブザーバーに通知するKVOを伝えることができます。また

、他の人が指摘しているとして、あなたはwillChangeValueForKey:didChangeValueForKey:電話を捨てると実装できます。minBため

+ (NSSet *) keyPathsForValuesAffectingMinA 
{ 
    return [NSSet setWithObject:@"type"]; 
} 

同じ、 もちろん。

次に、minAminBの読み取り専用プロパティを作成します。

それを行うさまざまな方法は主に文体的な好みです。

関連する問題