KVO for whole object properties
I can think of two options.
You could create a separate "master" property and make it depend on all your other properties.
@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]; }
If you observe
masterProperty
you'll be notified when any of the properties change.You use the Objective-C runtime to get a list of all the properties and observe them all.
- (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); }
What you could do is have a function to modify a particular property of the myObject...
-(void)setMyObjectName:(NSString*)name;
and then in the function have this code...
- (void)setMyObjectName:(NSString*)name
{
[self willChangeValueForKey:@"myObject"];
myObject.name = name;
[self didChangeValueForKey:@"myObject"];
}
This will then notify the observer when that property on myObject is changed.
Whever you need this doing use this pattern and you can get notified for any change on myObject.
::EDIT:: Having said that, you should be able to use...
[otherObject addObserver:self
forKeyPath:@"myObject.property1"
options:0
context:nil];
and that will observe property1 and do the same fort the other properties.
But this will mean adding an observer for each property individually.
Swift version of DrummerB answer, with an additional function to remove the observations (eg in 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)
}
}
}