Objective-C KVO不适用于C联合会

时间:2013-01-12 16:47:15

标签: objective-c key-value-observing unions

我需要在使用KVO的Objective-C类上观察union-typed属性,但似乎我没有运气。我做了一些实验:只要我使用的是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在这种情况下不起作用。

更新:为了清楚说明,这是一个简单的测试用例,它将struct属性上的KVO观察者与union属性上的KVO观察者进行比较。这些属性不相关。他们有独立的ivars和独立的内存支持商店。您可以删除struct属性并运行测试,结果仍然相同 - union属性没有KVO观察者事件。

1 个答案:

答案 0 :(得分:10)

属性与OP的问题无关。

我误解了发烧引起的幻觉。

工会在KVO / KVC中被淘汰出局。留下下面的文字,因为它仍然很有趣。


KVO无法通过观察记忆或播放任何此类棘手的诡计而起作用。它的工作原理是动态创建一个子类,覆盖setter方法,并在调用setter时自动调用willChange.../didChange...方法。

因此,您实际上拥有 2个 1个支持商店。然而,就KVO而言,它们完全相互隔离。

你想要的是依赖键。您可以使用+keyPathsForValuesAffectingValueForKey:在两个键之间创建依赖关系,这样调用setter就会触发另一个属性的更改。

我不知道它是否支持共同依赖;如果它支持有效的循环依赖。

或者,你应该能够覆盖setter来为另一个属性(以及被更改的属性)调用willChange/didChange


如果要么属性发生更改,如果您希望{em} 键触发willChange/didChange,则会使用相关的密钥。即如果你搞砸了struct,那么union会有效地改变,union属性的观察者应该看到一个意愿/做了改变,以响应设置结构版本。

我刚试过它。你是对的。工会有点奇怪。它破碎了。所有这些仍然是正确的,但它没有好处。

雷达提交:rdar:// problem / 13003794


噢......整洁。 KVO w /工会根本不起作用。看起来运行时根本不会识别出该类有一个名为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.'