17

Key Value Observing (KVO) の使用と、プロパティ変更の通知を受け取るための登録方法に満足しています。

[account addObserver:inspector
          forKeyPath:@"openingBalance"
             options:NSKeyValueObservingOptionNew
              context:NULL];

しかし、アカウント オブジェクトのすべてのプロパティの変更を監視したい場合、どうすればこれを達成できますか? 物件ごとに通知登録が必要ですか?

4

2 に答える 2

20

オブジェクトのすべてのプロパティの変更をサブスクライブする組み込み関数はないようです。

どのプロパティが正確に変更されたかを気にせず、クラスを変更できる場合は、それにダミー プロパティを追加して、他のプロパティの変更を観察できます (+ keyPathsForValuesAffectingValueForKeyまたは+keyPathsForValuesAffecting<Key>メソッドを使用):

// .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;
}

プロパティを監視するdummyと、オブジェクトのプロパティが変更されるたびに KVO 通知を受け取ります。

また、投稿されたコードのようにオブジェクト内のすべてのプロパティのリストを取得し、ループ内でそれぞれの KVO 通知をサブスクライブすることもできます (したがって、プロパティ値をハードコーディングする必要はありません) - このようにして、変更されたプロパティを取得します。必要に応じて名前を付けます。

于 2012-11-21T11:29:55.127 に答える
1

次の Swift コードは、david van brink によって提案されているように、各プロパティの観測を追加します。観測を削除する追加機能があります (例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)
        }
    }
}
于 2020-01-21T10:49:46.643 に答える