为什么在实现我自己的KVC setter/getter方法时会出现未捕获的异常

6 macos cocoa objective-c key-value-observing

我的模型类大多是用合成的setter/getter方法实现的,一切都很好.一切都很好地连接到用户界面.后来我才意识到,改变一个属性应该引起其他性质改变(改变type可能导致的变化minAmaxA),所以我手动写的二传手/ getter方法type属性.代码如下:

QBElementType

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

@implementation QBElementType
   @synthesize minRange;
   @synthesize maxRange;
@end
Run Code Online (Sandbox Code Playgroud)

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
Run Code Online (Sandbox Code Playgroud)

问题:从那时起,每当我更改Element的Type时,我都会得到一个未被捕获的异常:

无法为观察者<NSTableBinder ...>更新来自<QBElement ...>的密钥路径"type.minRange",很可能是因为更改了密钥"type"的值而没有发送适当的KVO通知.检查QBElement类的KVO-Compliance.

KVO-Compliance是否遗漏了一些明显的东西?为什么我会收到此错误?

And*_*sen 3

您不需要显式调用-willChangeValueForKey:and-didChangeValueForKey:因为您的 setter 已正确命名。对它们的调用将通过 KVC/KVO 机制的魔力自动添加。问题可能在于它们实际上被调用了两次。

另外,由于minAmaxA看起来只是从类型派生而来,因此您可以将它们设置为只读,并告诉 KVO 自动通知观察者 minA 和 maxA 已在任何时间发生变化type

@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
Run Code Online (Sandbox Code Playgroud)