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.'
Другие вопросы по тегам