是否可以添加观察者以获取通知是否修改了任何受监视对象属性?例如:
@interface OtherObject : NSObject
@property (nonatomic) MyObject* myObject;
@end
和
@interface MyObject : NSObject
@property (nonatomic) unsigned int property1;
@property (nonatomic) unsigned int property2;
@end
我想做点什么:
[otherObject addObserver:self
forKeyPath:@"myObject"
options:0
context:nil]
如果property1或property2被修改,则会收到通知。如果我注册了hold对象似乎不起作用(因为我修改了property1时没有真正修改myObject,所以这是有道理的。)
答案 0 :(得分:13)
我可以想到两个选择。
您可以创建一个单独的“主”属性,并使其依赖于您的所有其他属性。
@interface MyObject : NSObject
@property (nonatomic) id masterProperty;
@property (nonatomic) unsigned int property1;
@property (nonatomic) unsigned int property2;
@end
+ (NSSet *)keyPathsForValuesAffectingMasterProperty {
return [NSSet setWithObjects:@"property1", @"property2", nil];
}
如果您发现masterProperty
,则会在任何属性发生变化时通知您。
使用Objective-C运行时获取所有属性的列表并观察它们。
- (void)addObserverForAllProperties:(NSObject *)observer
options:(NSKeyValueObservingOptions)options
context:(void *)context {
unsigned int count;
objc_property_t *properties = class_copyPropertyList([self class], &count);
for (size_t i = 0; i < count; ++i) {
NSString *key = [NSString stringWithCString:property_getName(properties[i])];
[self addObserver:observer forKeyPath:key
options:options context:context];
}
free(properties);
}
答案 1 :(得分:2)
你可以做的是有一个函数来修改myObject的特定属性......
-(void)setMyObjectName:(NSString*)name;
然后在函数中有这段代码......
- (void)setMyObjectName:(NSString*)name
{
[self willChangeValueForKey:@"myObject"];
myObject.name = name;
[self didChangeValueForKey:@"myObject"];
}
这将在myObject上的属性发生更改时通知观察者。
如果您需要这样做,请使用此模式,您可以收到有关myObject的任何更改的通知。
:: EDIT :: 话虽如此,你应该可以使用......
[otherObject addObserver:self
forKeyPath:@"myObject.property1"
options:0
context:nil];
,这将观察property1并对其他属性执行相同的操作。
但这意味着要为每个属性单独添加一个观察者。
答案 2 :(得分:1)
DrummerB答案的快速版本,带有删除观察结果的附加功能(例如,在deinit
中):
extension NSObject {
func addObserverForAllProperties(
observer: NSObject,
options: NSKeyValueObservingOptions = [],
context: UnsafeMutableRawPointer? = nil
) {
performForAllKeyPaths { keyPath in
addObserver(observer, forKeyPath: keyPath, options: options, context: context)
}
}
func removeObserverForAllProperties(
observer: NSObject,
context: UnsafeMutableRawPointer? = nil
) {
performForAllKeyPaths { keyPath in
removeObserver(observer, forKeyPath: keyPath, context: context)
}
}
func performForAllKeyPaths(_ action: (String) -> Void) {
var count: UInt32 = 0
guard let properties = class_copyPropertyList(object_getClass(self), &count) else { return }
defer { free(properties) }
for i in 0 ..< Int(count) {
let keyPath = String(cString: property_getName(properties[i]))
action(keyPath)
}
}
}