Key Value Observing - how to observe all the properties of an object?

前端 未结 2 1240
故里飘歌
故里飘歌 2020-12-14 03:13

I am happy with the use of Key Value Observing (KVO), and how to register to receive notifications of property change:

[account addObserver:inspector
                


        
相关标签:
2条回答
  • 2020-12-14 03:19

    It seems there's no built-in function to subscribe for changes in all properties of the objects.

    If you don't care about which exactly property has changed and can change your class you can add dummy property to it to observe changes in other properties (using + keyPathsForValuesAffectingValueForKey or +keyPathsForValuesAffecting<Key> method):

    // .h. We don't care about the value of this property, it will be used only for KVO forwarding
    @property (nonatomic) int dummy;
    
    #import <objc/runtime.h>
    //.m
    + (NSSet*) keyPathsForValuesAffectingDummy{
    
        NSMutableSet *result = [NSMutableSet set];
    
        unsigned int count;
        objc_property_t *props = class_copyPropertyList([self class], &count);
    
        for (int i = 0; i < count; ++i){
            const char *propName = property_getName(props[i]);
            // Make sure "dummy" property does not affect itself
            if (strcmp(propName, "dummy"))
                [result addObject:[NSString stringWithUTF8String:propName]];
        }
    
        free(props);
        return result;
    }
    

    Now if you observe dummy property you'll get KVO notification each time any of object's properties is changed.

    Also you can get list of all properties in the object as in the code posted and subscribe for KVO notifications for each of them in a loop (so you don't have to hard code property values) - this way you'll get changed property name if you need it.

    0 讨论(0)
  • 2020-12-14 03:21

    The following Swift code adds observations for each property, as suggested by david van brink. It has 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)
            }
        }
    }
    
    0 讨论(0)
提交回复
热议问题