美文网首页
NSKey​Value​Observing

NSKey​Value​Observing

作者: 阿斯兰iOS | 来源:发表于2017-04-24 13:43 被阅读36次

    官方文档点这里:NSKey​Value​ObservingKey-Value Observing Programming Guide

    NSKey​Value​Observing (KVO) 非正式协议定义了一个机制,允许一个对象在其他对象的属性发生变化时,收到通知。


    <p>


    Overview


    <p>

    可以观察任意的对象属性,包括 simple attributes, to-one relationships, 和 to-many relationships。attributes 可以理解为标量,比如 int,或者 NSNumber 对象。to-one relationships 可以理解为一个对象,比如一个学生类对象。to-many relationships 可以理解为集合对象,比如 NSArray 对象。观察 to-many relationships 的观察者可以被通知变化的类型和发生变化的对象。

    NSObject 实现了 KVO,可以禁止自动通知和手动通知观察者。


    <p>

    Symbols


    Change Notification


    <p>

    - (void)observeValueForKeyPath:(NSString *)keyPath 
                          ofObject:(id)object 
                            change:(NSDictionary<NSKeyValueChangeKey,id> *)change 
                           context:(void *)context;
    
    
    • 通知观察者发生了变化。
    • key​Path,发生变化的属性。
    • object,发生变化的对象,被观察者。
    • change,包含变化的字典。可用的 key 有 newKey、oldKey、kindKey(比如 insert、replacement,具体看 NSKey​Value​Change 部分) 等,分别获取属性的新值、旧值、变化类型(比如插入、替换)。详情请看 Change Dictionary Keys 部分。
    • context,观察者注册 kvo 时提供的值。
    • 调用 add Observer: for Key Path: options: context: 注册观察者,调用 remove Observer: for Key Path: or remove Observer: for Key Path: context: 移除观察者。当目标发生变化时,观察者就会调用本函数。需要注意的是,调用访问器(getter 和 setter)才会触发 kvo。


    <p>


    Registering for Observation


    <p>

    - (void)addObserver:(NSObject *)observer 
             forKeyPath:(NSString *)keyPath 
                options:(NSKeyValueObservingOptions)options 
                context:(void *)context;
    
    
    • 注册观察者,接收 kvo 通知。
    • observer,观察者,必须实现 *observeValueForKeyPath: ofObject: change: context: *方法,收到通知时会调用。
    • key​Path,发生变化的属性。不能为 nil。
    • options,定义 kvo 通知要传递的内容,有 NSKeyValueObservingOptionNew、Old、Initial、Prior。比如 New 意味着通知的 change 字典包含变化之后的值,具体看 NSKey​Value​Observing​Options 部分。
    • context,随意的数据,传给观察者的 observeValueForKeyPath: ofObject: change: context: 方法。
    • 不会 retain 观察者和被观察者(Neither the object receiving this message, nor observer, are retained.)。记得调用 remove Observer: for Key Path: 或 remove Observer: for Key Path: context: 移除观察者。


    <p>

    - (void)removeObserver:(NSObject *)observer 
                forKeyPath:(NSString *)keyPath;
    
    
    • 移除对某个属性的观察。
    • 如果移除的对象并没有注册为观察者,会引发异常。
    • 在观察者被 deallocated 之前调用本函数,否则给释放掉的对象发送通知会引发异常。


    <p>

    - (void)removeObserver:(NSObject *)observer 
                forKeyPath:(NSString *)keyPath 
                   context:(void *)context;
    
    
    • 移除对某个属性的观察。
    • 如果移除的对象并没有注册为观察者,会引发异常。
    • 在观察者被 deallocated 之前调用本函数,否则给释放掉的对象发送通知会引发异常。
    • 一个对象可能会对相同的 key path 注册多次,可以根据 context 判断要移除哪一次。


    <p>


    Notifying Observers of Changes


    <p>

    - (void)willChangeValueForKey:(NSString *)key;
    
    
    • 属性将要发生变化时通知观察者。用于手动通知观察者。
    • change type 是 NSKey​Value​Change​Setting。
    • 注意,修改属性值之后,要调用 did​Change​Value​For​Key: 。
    • 极少重写本函数,如果重写,记得调用 super 的函数。


    <p>

    - (void)didChangeValueForKey:(NSString *)key;
    
    
    • 通知观察者,属性值已经发生变化。用于手动通知观察者。
    • 极少重写本函数,如果重写,记得调用 super 的函数。


    <p>

    - (void)willChange:(NSKeyValueChange)changeKind 
       valuesAtIndexes:(NSIndexSet *)indexes 
                forKey:(NSString *)key;
    
    
    • 通知观察者,一个 ordered to-many relationship(比如 NSArray 对象)的 indexes 位置的元素将要发生变化。用于手动通知观察者。
    • change,变化类型,具体看 NSKeyValueChange 部分。
    • indexes, 发生变化的元素下标集合。
    • key,属性名,比如 students。
    • 注意,属性值变化之后,要调用 did​Change:​values​At​Indexes:​for​Key:​ 。
    • 很少重写本函数,如果重写,记得调用 super 的函数。


    <p>

    - (void)didChange:(NSKeyValueChange)changeKind 
      valuesAtIndexes:(NSIndexSet *)indexes 
               forKey:(NSString *)key;
    
    
    • 通知观察者位于 indexes 的元素发生了变化。用于手动通知观察者。
    • change,变化类型,具体看 NSKeyValueChange 部分。
    • indexes, 发生变化的元素下标集合。
    • key,属性名,比如 students。
    • 很少重写本函数,如果重写,记得调用 super 的函数。


    <p>

    - (void)willChangeValueForKey:(NSString *)key 
                  withSetMutation:(NSKeyValueSetMutationKind)mutationKind 
                     usingObjects:(NSSet *)objects;
    
    
    • 通知观察者,一个 unordered to-many relationship(比如 NSSet 对象)将要发生什么类型的变化。用于手动通知。
    • key,属性名,比如 studentSet。
    • mutation​Kind,变化类型,比如交集、并集,具体看 NSKey​Value​Set​Mutation​Kind 部分。
    • objects,参与变化的对象,比如取交集需要两个集合对象。
    • 当发生变化之后,记得调用 did​Change​Value​For​Key:​with​Set​Mutation:​using​Objects: 函数。
    • 重写时记得调用父类方法。


    <p>

    - (void)didChangeValueForKey:(NSString *)key 
                 withSetMutation:(NSKeyValueSetMutationKind)mutationKind 
                    usingObjects:(NSSet *)objects;
    
    
    • 通知观察者,一个 unordered to-many relationship(比如 NSSet 对象)发生了什么类型的变化。用于手动通知。
    • key,属性名,比如 studentSet。
    • mutation​Kind,变化类型,比如交集、并集,具体看 NSKey​Value​Set​Mutation​Kind 部分。
    • objects,参与变化的对象,比如取交集需要两个集合对象。
    • 重写时记得调用父类方法。


    <p>


    Observing Customization


    <p>

    + (BOOL)automaticallyNotifiesObserversForKey:(NSString *)key;
    
    
    • 返回一个布尔值,表示是否支持自动 kvo。
    • 返回 YES 表示自动调用 will​Change​Value​For​Key:​/did​Change​Value​For​Key:​ 和 will​Change:​values​At​Indexes:​for​Key:​/did​Change:​values​At​Indexes:​for​Key:,或者是遵从 kvc 的方法。
    • 默认返回 YES。


    <p>

    + (NSSet<NSString *> *)keyPathsForValuesAffectingValueForKey:(NSString *)key;
    
    
    • 返回 key path 的集合对象,其对应的属性值影响参数 key 对应的属性。比如姓名由姓和名决定。
    • 默认实现是查找类似 +key​Paths​For​Values​Affecting<Key> 的方法,如果找到了就返回类似方法的结果集。可以重写该方法,但要调用 super 的方法。具体看 kvo 编程指导,文章顶部有链接。


    <p>

    @property void *observationInfo;
    
    
    // demo。self 是控制器对象。
    - (void)testObservationInfo {
        UIViewController *vc = [UIViewController new];
        [self addObserver:vc forKeyPath:@"view" options:NSKeyValueObservingOptionNew context:NULL];
        id observationInfo = self.observationInfo;
    }
    
    • 一个指针,指向所有观察者的标识信息。
    • The default implementation of this method retrieves the information from a global dictionary of observed objects keyed by memory addresses.
    • For improved performance, both this property and observation​Info can be overridden to store the opaque data pointer in an instance variable. Overrides of this property must not attempt to send messages to the stored data.
    • 可以参考这篇文章:http://www.bkjia.com/IOSjc/993206.html
    • 实际指向一个 NSKeyValueObservationInfo 对象,里面有个数组存放 NSKeyValueObservance 对象。这两个类在文档中并没有找到。NSKeyValueObservance 对象包含了观察者、观察的属性、依赖的属性、注册观察者时的 context 等。如下图所示,观察者是一个控制器对象,被观察的是 view 属性,context 是 NULL。
    observationInfo.png


    <p>


    <p>


    Constants


    <p>

    NSKey​Value​Change
    typedef NS_ENUM(NSUInteger, NSKeyValueChange) {
        NSKeyValueChangeSetting = 1,
        NSKeyValueChangeInsertion = 2,
        NSKeyValueChangeRemoval = 3,
        NSKeyValueChangeReplacement = 4,
    };
    
    • 表示变化类型。 用于函数 observe​Value​For​Key​Path:​of​Object:​change:​context:​ 的 change 字典的 NSKey​Value​Change​Kind​Key 对应的值。
    • setting 表示被设置了新值。
    • insertion 表示一个 to-many relationship 插入了新的元素。
    • removal 表示一个 to-many relationship 删除了元素。
    • replacement 表示一个 to-many relationship 替换了元素。


    <p>

    NSKey​Value​Observing​Options
    typedef NS_OPTIONS(NSUInteger, NSKeyValueObservingOptions) {
        NSKeyValueObservingOptionNew = 0x01,
        NSKeyValueObservingOptionOld = 0x02,
        NSKeyValueObservingOptionInitial NS_ENUM_AVAILABLE(10_5, 2_0) = 0x04,
        NSKeyValueObservingOptionPrior NS_ENUM_AVAILABLE(10_5, 2_0) = 0x08
    };
    
    • 用于函数 add​Observer:​for​Key​Path:​options:​context: 的参数​,决定函数 observe​Value​For​Key​Path:​of​Object:​change:​context: 的 change 字典包含哪些键值对。传 0 使得 change 字典不包含其他键值对,除了 NSKey​Value​Change​Kind​Key。
    • new 表示 change 字典包含 NSKeyValueChangeNewKey 键值对,可以获取新值。
    • old 表示 change 字典包含 NSKeyValueChangeOldKey 键值对,可以获取旧值。
    • initial 用于获取初始值,和 new 一起使用。在 add​Observer:​for​Key​Path:​options:​context: 返回之前,就会发送一次通知。对于观察者来说是新值,所以和 new 一起使用,change 字典会包含 NSKeyValueChangeNewKey 键值对,可以获取初始值。
    • prior 表示发送两次通知,在发生变化前后各一次。发生变化前发送的通知的 change 字典里面有个 NSKeyValueChangeNotificationIsPriorKey,对应的值是表示 YES 或者 NO 的 NSNumber 对象,但字典不会包含 NSKeyValueChangeNewKey。发生变化后发送的通知的 change 字典,和不使用 prior 是一样的,也就是没有 NSKeyValueChangeNotificationIsPriorKey 了(When this option is specified the change dictionary in a notification sent after a change contains the same entries that it would contain if this option were not specified )。用于手动通知的时候,有机会调用 -will​ChangeValueForKey: 方法,通知会跟着变化的属性的观察者(比如 firstName 要变化了,想手动通知 fullName 的观察者)。


    <p>

    Change Dictionary Keys
    NSKeyValueChangeKey const NSKeyValueChangeKindKey;
    NSKeyValueChangeKey const NSKeyValueChangeNewKey;
    NSKeyValueChangeKey const NSKeyValueChangeOldKey;
    NSKeyValueChangeKey const NSKeyValueChangeIndexesKey;
    NSKeyValueChangeKey const NSKeyValueChangeNotificationIsPriorKey;
    
    • 用于 observe​Value​For​Key​Path:​of​Object:​change:​context:​ 函数的change 字典。
    • kindKey 表示变化类型,具体看 NSKey​Value​Change 部分。
    • newKey 表示变化后的值。注册观察者时用的 NSKeyValueObservingOptionNew,字典才会有这个键值对。如果 kindKey 是 NSKeyValueChangeInsertion 或者 replacement,newKey 对应的值是一个 NSArray 对象,包含插入或者被替换的元素。
    • oldKey 表示变化前的值。注册观察者时用的 NSKeyValueObservingOptionOld,字典才会有这个键值对。如果 kindKey 是 NSKeyValueChangeRemoval 或者 replacement,newKey 对应的值是一个 NSArray 对象,包含删除或者被替换的元素。
    • indexesKey 表示发生变化的元素下标,值是 NSIndex​Set 对象,如果 kindKey 是 NSKeyValueChangeInsertion、replacement、removal 的话。
    • Notification​Is​Prior​Key 表示是否变化前后发送通知,如果注册观察者时用的 NSKeyValueObservingOptionPrior。


    <p>

    NSKey​Value​Set​Mutation​Kind
    typedef NS_ENUM(NSUInteger, NSKeyValueSetMutationKind) {
        NSKeyValueUnionSetMutation = 1,
        NSKeyValueMinusSetMutation = 2,
        NSKeyValueIntersectSetMutation = 3,
        NSKeyValueSetSetMutation = 4
    };
    
    • 用于 will​Change​Value​For​Key:​with​Set​Mutation:​using​Objects:​ 和 did​Change​Value​For​Key:​with​Set​Mutation:​using​Objects: 函数的参数。含义与 NSMutable​Set 的方法 union​Set:​、minus​Set:​、intersect​Set:​ 和 set​Set: 相对应。
    • Union​ 表示发生了并集。change 字典的NSKey​Value​Change​Kind​Key 对应的值是 NSKey​Value​Change​Insertion。
    • Minus 表示两个集合相减,也就是减去两个集合中相同的元素。change 字典的NSKey​Value​Change​Kind​Key 对应的值是 NSKey​Value​Change​Removal。
    • Intersect 表示求交集,删除与另一个集合不相同的元素。change 字典的NSKey​Value​Change​Kind​Key 对应的值是 NSKey​Value​Change​Removal。
    • Set 表示集合的所有元素被另一个集合的元素代替。change 字典的NSKey​Value​Change​Kind​Key 对应的值是 NSKey​Value​Change​Replacement。

    相关文章

      网友评论

          本文标题:NSKey​Value​Observing

          本文链接:https://www.haomeiwen.com/subject/ypfyottx.html