Objective-C KVO не работает с профсоюзами C
Мне нужно наблюдать свойства типа union в классе Objective-C, используя KVO, но, похоже, мне не повезло с этим. Я провел несколько экспериментов: все работает нормально, пока я использую C-структуру. Как только я заменяю структуру на объединение, автоматический KVO больше не работает (observeValueForKeyPath
не называется).
Вот мой маленький тестовый класс:
AppDelegate.h:
#import <Cocoa/Cocoa.h>
typedef union {
float data[3];
struct {
float x,y,z;
};
} vec3union;
typedef struct {
float x,y,z;
} vec3struct;
@interface AppDelegate : NSObject <NSApplicationDelegate>
@property (assign) IBOutlet NSWindow *window;
@property (assign) vec3struct vectorStructValue;
@property (assign) vec3union vectorUnionValue;
@end
AppDelegate.m:
@implementation AppDelegate
@synthesize vectorStructValue = _vectorStructValue;
@synthesize vectorUnionValue = _vectorUnionValue;
- (void)dealloc
{
[super dealloc];
}
- (void)applicationDidFinishLaunching:(NSNotification *)aNotification
{
[self addObserver:self forKeyPath:@"vectorStructValue" options:NSKeyValueObservingOptionNew context:nil];
[self addObserver:self forKeyPath:@"vectorUnionValue" options:NSKeyValueObservingOptionNew context:nil];
self.vectorStructValue = (vec3struct){1,2,3};
self.vectorUnionValue = (vec3union){4,5,6};
}
- (void)observeValueForKeyPath:(NSString *)keyPath ofObject:(id)object change:(NSDictionary *)change context:(void *)context
{
NSLog(@"keyPath %@ did change, object: %@", keyPath, [object description]);
}
@end
Выход:
2013-01-12 17:38:26.447 KVOTest[57522:303] keyPath vectorStructValue did change, object: <AppDelegate: 0x100614200>
Я делаю что-то не так или это ошибка или отсутствующая функция в реализации Objective-C /KVO?
Примечание. Я знаю, что могу реализовать это вручную, переопределив установщик свойств, но суть этого вопроса не в этом. Ответ должен дать мне представление о том, почему автоматический KVO не работает в этом случае.
Обновление: просто чтобы прояснить это, это простой тестовый пример, сравнивающий KVO-наблюдатель в свойстве struct со наблюдателем в свойстве union. Эти свойства не взаимосвязаны. У них есть независимые ивары с независимыми хранилищами памяти. Вы можете удалить свойство struct и запустить тест, все тот же результат - никакого события-наблюдателя KVO для свойства union.
1 ответ
Свойства не связаны в вопросе OP.
Я неправильно понял это в галлюцинации, вызванной лихорадкой.Союзы просто разорились в КВО / КВК. Оставляя текст ниже, потому что это все еще интересно.
KVO не работает, наблюдая за памятью или играя какие-то хитрые махинации вроде этого. Он работает путем динамического создания подкласса на лету, переопределяя метод установки и вызывая willChange.../didChange...
методы автоматически, когда вызывается сеттер.
Таким образом, у вас фактически есть 2 свойства с 1 резервным хранилищем. Что касается КВО, то они находятся в полной изоляции друг от друга.
То, что вы хотите, это зависимые ключи. Ты можешь использовать +keyPathsForValuesAffectingValueForKey:
создать зависимость между двумя ключами так, чтобы вызов любого из установщиков вызвал изменение другого свойства.
Я не знаю, поддерживает ли это совместную зависимость; если он поддерживает то, что фактически будет круговой зависимостью.
Кроме того, вы должны иметь возможность переопределить сеттер для вызова willChange/didChange
для другого свойства (а также для свойства, подлежащего изменению).
Связанные ключи будут использоваться, если вы хотите willChange/didChange
запускать оба ключа в случае изменения какого- либо свойства. Т.е. если вы гадите со структурой, объединение эффективно изменится, и наблюдатели свойства объединения должны увидеть желание / сделал изменение в ответ на установку версии структуры.
Я только что проверил это. Ты прав. Что-то странное с профсоюзами. Это совершенно сломано. Все вышеперечисленное все еще остается верным, но это не приносит пользы.
Радар подал: rdar://problem/13003794
Ооо... аккуратно. КВО с профсоюзами просто не работает. Похоже, что среда выполнения просто не распознает, что у класса есть ключ vectorUnionValue
совсем.
Я добавил:
+ (NSSet *)keyPathsForValuesAffectingVectorStructValue
{
return [NSSet setWithObject:@"vectorUnionValue"];
}
+ (NSSet *)keyPathsForValuesAffectingVectorUnionValue
{
return [NSSet setWithObject:@"vectorStructValue"];
}
Что вызвало исключение во время выполнения:
2013-01-12 12:05:11.877 djkdfjkdfjkdf[51598:303] *** Terminating app due to uncaught exception 'NSUnknownKeyException', reason: '[<AppDelegate 0x10010a520> valueForUndefinedKey:]: this class is not key value coding-compliant for the key vectorUnionValue.'