zoukankan      html  css  js  c++  java
  • KeyValue Observing

    KVO和KVC在Cocoa中往往联合使用,是很好的工具。在之前的文章中我们介绍了KVC,这里要介绍一下KVO了。

    Key-value observing provides a mechanism that allows objects to be notified of changes to specific properties of other objects. It is particularly useful for communication between model and controller layers in an application. (In OS X, the controller layer binding technology relies heavily on key-value observing.) A controller object typically observes properties of model objects, and a view object observes properties of model objects through a controller. In addition, however, a model object may observe other model objects (usually to determine when a dependent value changes) or even itself (again to determine when a dependent value changes). 

    怎样使用KVO?

    要使用KVO,需要按照下面的步骤进行:

    • The observed class must be key-value observing compliant for the property that you wish to observe
    • You must register the observing object with the observed object, using the method addObserver:forKeyPath:options:context:
    • The observing class must implement observeValueForKeyPath:ofObject:change:context:
    • 当不再需要observe时,observer/或者其他 应该发送removeObserver:forKeyPath:给observed object
    • 另外:
      • 1. 如果一个property依赖于其他对象的一个或者多个attribute,若某个attribute变化了,那dependent property也应该被认为发生变化,而发出notification。这时,该property所在的类需要实现keyPathsForValuesAffectingValueForKey:或者keyPathsForValuesAffecting<Key>。但如果使用category扩展出的的property时,就只能使用keyPathsForValuesAffecting<Key>这种方法了,因为在category中只能加新方法,不能override方法。
      • 2. 上面介绍的方法keyPathsForValuesAffectingValueForKey:并不支持to-many relationship。解决办法有:将父类对象注册为子类对象所有相关属性的observer。而且在有子对象被加入或者移除时,需要更新这种observing关系。也可以使用CoreData来解决,后面再介绍。

    When the value of an observed property of an object changes, the observer receives an observeValueForKeyPath:ofObject:change:context: message. All observers must implement this method.

    KVO是使用一种叫做"isa-swizzling"的技术实现的,其工作原理如下:

    The isa pointer, as the name suggests, points to the object's class which maintains a dispatch table. This dispatch table essentially contains pointers to the methods the class implements, among other data.

    When an observer is registered for an attribute of an object the isa pointer of the observed object is modified, pointing to an intermediate class rather than at the true class. As a result the value of the isa pointer does not necessarily reflect the actual class of the instance.

    You should never rely on the isa pointer to determine class membership. Instead, you should use the class method to determine the class of an object instance.

    KVO Compliance

    对某个observed property要想让其KVO Compliance,这个类需要做到以下几点:

    1. 该类提供必要的方法使这个property 是KVC Compliant的。

    2. 这个类能正确发出KVO change notification;

    3. 若某个Property依赖于其他几个Property(称为dependent keys),都应该被注册好

    上面这3点是 '与' 的关系,不是 '或' 的关系。有两种方法可以使得change notification被发出来,一个是automatic support,它是NSObject提供的,并默认提供给所有KVC compliant的类的Properties,如果我们按照标准的Cocoa编程规范,我们就是在用它;一个是manual notification,它可以在notification被发出时有更多控制。

    NSObject provides a basic implementation of automatic key-value change notification. Automatic key-value change notification informs observers of changes made using key-value compliant accessors, as well as the key-value coding methods. Automatic notification is also supported by the collection proxy objects returned by, for example, mutableArrayValueForKey:.

    上面这段是说,如果我们使用Accessor方法或者KVC 方法(setValue:forKey setValue:forKeyPath等)改变属性的值都会自动发出notification。

    Manual change notification provides more granular control over how and when notifications are sent to observers. This can be useful to help minimize triggering notifications that are unnecessary, or to group a number of changes into a single notification.

    A class that implements manual notification must override the NSObject implementation of automaticallyNotifiesObserversForKey:. It is possible to use both automatic and manual observer notifications in the same class. For properties that perform manual notification, the subclass implementation of automaticallyNotifiesObserversForKey: should return NO. A subclass implementation should invoke super for any unrecognized keys. 

    上面这段说Manual change notification往往配合automaticallyNotifiesObserversForKey:一起使用。如果一个Property已经是KVC Compliant的了,那意味着这个Property已经默认支持automatic notification了,我们要让其做manaul notification,就要覆盖automaticallyNotifiesObserversForKey:,使其不要多automatic notification。但是如果一个instance variable或者attribute并不是KVC Compliance的,而它仍然希望发出notification,那么就不需要覆盖automaticallyNotifiesObserversForKey:了。下面是一个automaticallyNotifiesObserversForKey:的例子:

    + (BOOL)automaticallyNotifiesObserversForKey:(NSString *)theKey {
     
        BOOL automatic = NO;
        if ([theKey isEqualToString:@"openingBalance"]) {
            automatic = NO;
        }
        else {
            automatic = [super automaticallyNotifiesObserversForKey:theKey];
        }
        return automatic;
    }

    将automatic notification关闭后,就需要调用willChangeValueForKey:didChangeValueForKey:来实现通知行为,如果一个操作导致多个key发生变化,需要嵌套调用。下面是一个例子:

    - (void)setOpeningBalance:(double)theBalance {
        [self willChangeValueForKey:@"openingBalance"];
        [self willChangeValueForKey:@"itemChanged"];
        _openingBalance = theBalance;
        _itemChanged = _itemChanged+1;
        [self didChangeValueForKey:@"itemChanged"];
        [self didChangeValueForKey:@"openingBalance"];
    }
  • 相关阅读:
    Qt BarChart实践
    Qt Charts_Audio实践
    Qt 报错LINK2019:无法解析的外部符号
    Qt Charts实践
    Qt Qwdget 汽车仪表知识点拆解8 淡入效果
    因果图法设计测试用例
    Jsoup获取部分页面数据失败 Unhandled content type. Must be text/*, application/xml, or application/xhtml+xml
    loadrunner入门篇
    如何对jmeter设置IP欺骗
    jmeter录制移动端脚本
  • 原文地址:https://www.cnblogs.com/whyandinside/p/2955114.html
Copyright © 2011-2022 走看看