我需要使用 KVO 在 Objective-C 类上观察联合类型的属性,但我似乎没有运气。我做了一些实验:只要我使用 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 实现中的错误或缺失的功能?
注意:我知道我可以通过覆盖属性 setter 来手动实现它,但这不是这个问题的重点。答案应该让我了解为什么自动 KVO 在这种情况下不起作用。
更新:为了清楚起见,这是一个简单的测试用例,比较结构属性上的 KVO 观察器和联合属性上的观察器。这些属性不相关。他们有独立的ivars和独立的内存后备存储。您可以删除 struct 属性并运行测试,结果仍然相同——联合属性没有 KVO 观察器事件。
最佳答案
属性与 OP 的问题无关。
我在发烧引起的幻觉中误读了这一点。工会在 KVO/KVC 中遭到彻底破坏。留下下面的文字,因为它仍然很有趣。
KVO 无法通过观察内存或玩任何此类棘手的恶作剧来工作。它的工作原理是动态创建子类,重写 setter 方法,并在调用 setter 时自动调用 willChange.../didChange...
方法。
因此,您实际上拥有 2 个属性 和 1 个后备 存储。不过,就 KVO 而言,它们彼此完全隔离。
你想要的是依赖键。您可以使用 +keyPathsForValuesAffectingValueForKey:
在两个键之间创建依赖关系,这样调用任何一个 setter 都会触发另一个属性的更改。
我不知道它是否支持相互依赖;如果它支持有效的循环依赖。
或者,您应该能够覆盖 setter 以调用 willChange/didChange
其他属性(以及正在更改的属性)。
如果您希望 willChange/didChange
在任一属性更改 时为两个 键触发,则将使用相关键。 IE。如果你弄乱了结构,联合会有效地改变,并且联合属性的观察者应该看到一个 will/did 改变以响应设置结构版本。
我刚测试过。你是对的。工会有些奇怪。它完全坏了。以上所有内容仍然成立,但没有任何好处。
雷达归档:rdar://problem/13003794
哦...整洁。带工会的 KVO 根本行不通。运行时似乎根本没有识别出该类有一个名为 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.'
关于Objective-C KVO 不适用于 C 联合体,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/14295505/