• ios 中 KVO


    KVO(Key value observe)键值观察,是ios中的一种核心的概念,简单的理解为当某一个对象A(或者多个对象)要想监听对象的B的一个或者多个属性发生变化时,就是用这种机制。

    1.  KVO的优点 

            当某个对象有个属性改变,KVO会自动的消息通知对方,这样的架构有多种好处。首先开发人员不需要自己去实现这样的方案:每次属性改变了就发送消息通知,这是KVO机制的最大优点,因为这个方案已经被明确定义,获得框架级的支持,可以方便的采用,开发人员不需要添加任何代码,不需要设计自己的开发者模型,直接就可以在工程里使用,其次KVO的架构非常强大,可以很容易的支持多个观察者观察同一个属性,以及相关的值           

         2、缺点,实时监听对象属性值的改变,非常消耗系统的性能。

         KVO 的面试题。

        1、NSNotification和KVO的区别和用法是什么?什么时候应该使用通知,什么时候应该使用KVO,它们的实现上有什么区别吗?如果用protocol和delegate(或者delegate的Array)来实现类似的功能可能吗?如果可能,会有什么潜在的问题?如果不能,为什么?

        答:KVO只能监测属性的变化,通过NSString类型的属性名来实现。但是实现了自动监测,当属性值变化时,会自动通知观察者,不用再添加代码了。

              NSNotification比较灵活,可以监测的内容较多,但是需要被观察者手动发送通知,观察者才能响应。

              protocol通过添加一个NSArray也能实现类似的功能,但是实现上需要自己处理delegate的添加与删除,自己在属性变化时手动通知,较繁琐,易出错

    通知机制简介

    /**

     *  NSNotificationCenter 两个对象之间传递消息,或者多个对象之间传递消息

     *  a 对象触发了某个事件(a对象不能完成),需要b对象完成,a对象(void)postNotificationName:(NSString *)aName object:(id)anObject;

     *  postNotificationName 发送消息的名字

     *  object 发送给哪个对象

     *  - (void)addObserver:(id)observer selector:(SEL)aSelector name:(NSString *)aName object:(id)anObject; 谁接收通知,接收到通知后实现的方法(SEL)aSelector 

     *  removeObserver移除通知

     */

        下面的KVO的Demo代码:

     

      1 Person.h内容
      2 
      3 #import <Foundation/Foundation.h>
      4 
      5 @interface Person : NSObject
      6 
      7 @property (nonatomic , copy) NSString *name;
      8 @property (nonatomic , assign) int  age;
      9 
     10 //- (void)dogNameChange;
     11 
     12 //- (void)dogAgeChange;
     13 
     14 @end
     15 
     16 
     17 Person.m文件内容
     18 #import "Person.h"
     19 
     20 @implementation Person
     21 
     22 //监听者实现方法
     23 - (void)observeValueForKeyPath:(NSString *)keyPath ofObject:(id)object change:(NSDictionary *)change context:(void *)context
     24 {
     25     if ([keyPath isEqual:@"name"]) //dog的name属性改变了
     26     {
     27         NSLog(@"Dog - name- change,old:%@ ,new:%@;context = %@",[change objectForKey:NSKeyValueChangeOldKey],[change objectForKey:NSKeyValueChangeNewKey],context);
     28         
     29     }
     30     
     31     if ([keyPath isEqual:@"age"]) //dog的age属性改变了
     32     {
     33         NSLog(@"Dog - age - change,old:%@ ,new:%@;context = %@",[change objectForKey:NSKeyValueChangeOldKey],[change objectForKey:NSKeyValueChangeNewKey],context);
     34     }
     35 }
     36 
     37 //- (NSString *)description
     38 //{
     39 //    return [NSString stringWithFormat:@"name - %@, age - %d",self.name,self.age];
     40 //}
     41 //
     42 //
     43 //- (void)dogNameChange
     44 //{
     45 //    NSLog(@"dogNameChange");
     46 ////    [self removeObserver:self forKeyPath:@"name"];
     47 //}
     48 //
     49 //- (void)dogAgeChange
     50 //{
     51 //     NSLog(@"dogAgeChange");
     52 //}
     53 
     54 @end
     55 
     56 Dog.h内容
     57 
     58 #import <Foundation/Foundation.h>
     59 
     60 @class Person;
     61 @interface Dog : NSObject
     62 
     63 
     64 @property (nonatomic , weak) Person *onwer;
     65 @property (nonatomic , assign) NSInteger age;
     66 @property (nonatomic , copy) NSString *name;
     67 
     68 @end
     69 
     70 Dog.m内容
     71 
     72 #import "Dog.h"
     73 
     74 @implementation Dog
     75 
     76 
     77 @end
     78 
     79 ViewController.m内容
     80 
     81 #import "SDViewController.h"
     82 #import "Person.h"
     83 #import "Dog.h"
     84 
     85 @implementation SDViewController
     86 
     87 - (void)viewDidLoad
     88 {
     89     [super viewDidLoad];
     90      Person *p = [[Person alloc] init];
     91     p.name = @"张三";
     92     p.age = 18;
     93     
     94     Dog *d = [[Dog alloc] init];
     95     d.age = 10;
     96     d.name = @"老狗";
     97 
     98      //KVO演练 -- 监听某个对象属性的改变
     99     [d addObserver:p forKeyPath:@"age" options:(0x01 | 0x02) context:@"helloage"];
    100     [d addObserver:p forKeyPath:@"name" options:(0x01 | 0x02) context:@"helloname"];
    101     
    102     //KVC赋值
    103     [d setValue:@(28) forKeyPath:@"age"];
    104     [p setValue:@"李四" forKeyPath:@"name"];
    105     [p setValue:@(10) forKeyPath:@"age"];
    106     [d setValue:@"小狗狗" forKeyPath:@"name"];
    107     
    108 //    [d removeObserver:p forKeyPath:@"name"]; //移除KVO
    109 //    [d removeObserver:p forKeyPath:@"age"]; //移除KVO
    110 
    111    
    112 }

    KVO中的头文件中重要的方法简介

    /*由于接收器已经被注册为在相对于物体的关键路径价值的观察者,被通知更改该值。 
    
    变更字典总是包含NSKeyValueChangeKindKey项,其值是一个NSNumber包装的NSKeyValueChange(使用 - [NSNumber的unsignedIntegerValue])。 NSKeyValueChange的意义取决于什么样的属性和关键线路识别: 
         - 对于任何类型的属性(属性,以一对一的关系,或有序或无序的一对多关系)NSKeyValueChangeSetting表示该观察对象已经收到了-setValue:forKey:消息,或者说,键 - 值编码兼容的设置方法密钥已被调用,或者一个-willChangeValueForKey:/ - didChangeValueForKey:对以其他方式被调用。 
         - 对于_ordered_一对多的关系,NSKeyValueChangeInsertion,NSKeyValueChangeRemoval和NSKeyValueChangeReplacement表明,突变的消息已发送到由-mutableArrayValueForKey返回的数组:发送给对象的消息,或者发送到由-mutableOrderedSetValueForKey返回的有序集合:消息发送给对象,或者说,键值中的一个编码标准的阵列或有序集合突变方法的关键已被调用,或者一个-willChange:valuesAtIndexes:forKey:/ - didChange:valuesAtIndexes:forKey:对有否则被调用。 
         - 对于_unordered_一对多的关系,NSKeyValueChangeInsertion,NSKeyValueChangeRemoval和NSKeyValueChangeReplacement(在Mac OS10.4中引入)表明,突变的消息已发送到由-mutableSetValueForKey返回的集合:发送给对象的消息,或那一个键 - 值编码兼容的一套基因突变的方法对密钥已被调用,或者一个 -willChangeValueForKey:withSetMutation:usingObjects:/-didChangeValueForKey:withSetMutation:usingObjects:对了,否则被调用。 
    
    对于任何形式的财产,变更字典有一个NSKeyValueChangeNewKey项,如果NSKeyValueObservingOptionNew在观察者注册时指定,这是正确的一种变化,这是不是事先通知。变更字典包含NSKeyValueChangeOldKey如果指定NSKeyValueObservingOptionOld,这是正确的一种变化。请参阅该NSKeyValueObserverNotification非正式协议的方法是什么这些条目的值可以是评论。 
    
    对于一个_ordered_一对多的关系,变更字典总是包含一个NSKeyValueChangeIndexesKey条目的值是包含插入,删除或替换的对象的索引,除非该变化是NSKeyValueChangeSetting一个NSIndexSet。 
    
    如果NSKeyValueObservingOptionPrior(中的Mac OS10.5引入)指定在观察者登记时间,而该通知是一个先前被发送到的变化,结果,变更字典包含NSKeyValueChangeNotificationIsPriorKey项,其值被一个NSNumber包装纸是(用 - [NSNumber的boolValue])。 
    
    背景始终是在观察者报名时间的推移,在同一个指针。*/
    
    //监听者实现方法
    - (void)observeValueForKeyPath:(NSString *)keyPath ofObject:(id)object change:(NSDictionary *)change context:(void *)context;
    //注册观察者 -- observer 谁在监听, keyPath -- 监听哪一个属性值 options -- 新的值与旧的值 context -- 传送给observer 的消息
    - (void)addObserver:(NSObject *)observer forKeyPath:(NSString *)keyPath options:(NSKeyValueObservingOptions)options context:(void *)context;

    //移除观察者 - (void)removeObserver:(NSObject *)observer forKeyPath:(NSString *)keyPath context:(void *)context NS_AVAILABLE(10_7, 5_0); - (void)removeObserver:(NSObject *)observer forKeyPath:(NSString *)keyPath;

      

  • 相关阅读:
    selenium 的页面对象模型Page Object
    PostMan的在线安装和简单使用
    用Jmeter对数据库执行压力测试
    常用的Linux系统命令
    摘:《自动化测试技术领航》
    WEB接口测试之Jmeter接口测试自动化 (四)(持续构建)
    WEB接口测试之Jmeter接口测试自动化 (二)(数据分离)
    WEB接口测试之Jmeter接口测试自动化 (一)(初次接触)
    性能测试篇 :Jmeter监控服务器性能
    UI自动化测试篇 :ReportNG替代TestNG自带html版测试报告初探
  • 原文地址:https://www.cnblogs.com/ndyBlog/p/3955885.html
Copyright © 2020-2023  润新知