Почему я получаю необработанное исключение при реализации моих собственных методов установки / получения KVC
Мои классы моделей в основном реализованы с помощью синтезированных методов установки / получения, и все было хорошо. Все было приятно подключено к пользовательскому интерфейсу. Позже я понял, что изменение одного свойства должно привести к изменению других свойств (изменение type
может вызвать изменения в minA
а также maxA
) поэтому я вручную написал методы setter/getter для type
имущество. Код следует:
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
ВОПРОС: С тех пор всякий раз, когда я меняю тип элемента, я получаю неперехваченное исключение:
Невозможно обновить для наблюдателя
для пути ключа "type.minRange" из , скорее всего, потому что значение для ключа "тип" было изменено без отправки соответствующего уведомления KVO. Проверьте KVO-соответствие класса QBElement.
Есть ли что-то очевидное, чего мне не хватает в KVO-Compliance? Почему я получаю эту ошибку?
3 ответа
Вам не нужно явно звонить -willChangeValueForKey:
а также -didChangeValueForKey:
потому что ваш сеттер назван правильно. Звонки к ним будут добавляться автоматически с помощью магии машин KVC/KVO. Проблема может заключаться в том, что их фактически вызывают дважды.
Кроме того, так как кажется, что minA
а также maxA
просто получены из типа, вы можете сделать их доступными только для чтения и сказать 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
Реализация ручного установщика не означает, что вам обязательно нужно внедрять ручные уведомления KVO. Они абсолютно необходимы, если вы обновляете резервный ivar для свойства, не проходя через установщик. KVO автоматически заменит ваши сеттеры версиями, которые вызывают методы will/didChange до и после вызова "настоящего" сеттера. Если вы хотите вызывать их самостоятельно в своем установщике (например, вам нужно более точное управление при их вызове), вам необходимо переопределить метод +automaticallyNotifiesObserversForKey:
возвращать NO
для тебя type
ключ.
Я предполагаю, что причина, по которой вы получаете ошибку, состоит в том, что механизм KVO видит, что вы вызвали [self willChangeValueForKey:@"type"]
два раза подряд (один раз через КВО "Волшебный", один раз вручную) без вызова [self didChangeValueForKey:@"type"]
,
Как уже отмечали другие, вы можете отказаться от willChangeValueForKey:
, didChangeValueForKey:
звонки и реализовать:
+ (NSSet *) keyPathsForValuesAffectingMinA
{
return [NSSet setWithObject:@"type"];
}
То же самое для minB
, конечно.
Тогда сделай minA
а также minB
свойства только для чтения.
Однако разные способы сделать это во многом стилистические предпочтения.