zoukankan      html  css  js  c++  java
  • KVC和KVO

    kvc(key value coding),它是一种可以直接通过字符串的名字(key)来访问类属性的机制,可以直接通过set value forKey 和valueforkey方法来给实例变量赋值和取值,kvc的机制就是首先判断属性是否有get和set方法,如果不存在将在内部查找_key 和 key的实例变量,如果没有将会调用setvalueforundefinedkey,如果没有这个方法,运行报错



    优点:可以减少代码量,没有properey声明的变量也可以通过kvc来设置
    缺点:如果key值写错,编写时不会报错,运行时会报错

    kvo:一个对象可以观察另一个对象的值,并且能够发现值的变化,或者说一个对像与另一个对象保持同步的一种方法,当被观察的对象状态发生改变时,观察者马上做出相应,但是有一个缺点,它只能对对象的属性做出反应,而不会对象的方法做出反应

    比如 svpulltorefresh,上啦加载,下拉刷新就用到了这个类

    kvo的优点:可以同步对象,能够观察对象的最新值和先前值,而且不需要额外的代码来允许观察者能够被观察
    缺点:当我们注册监听的时候,监听对象的属性和写错了,程序编译时不会报错,因为是字符串编译器也不会检查

    KVC是KeyValue Coding的简称,它是一种可以直接通过字符串的名字(key)来访问类属性的机制。而不是通过调用Setter、Getter方法访问

    具体的例子:

    1.创建一个people类,继承与NSObject

       @interface People : NSObject
       @property(nonatomic,copy)NSString *name;//people的属性
       @end

     当我们在类外访问的时候,可以通过打点调用属性

        People *p=[People new];//创建一个people
        p.name=@"李四";

    也可以通过kvc的方式来调用

        People *people=[People new];
        [people setValue:@"张三" forKey:@"name"];
        NSLog(@"%@",people.name);//张三
        NSString *name=[people valueForKey:@"name"];
        NSLog(@"%@",name);
    你或许说了,打点调用不是可以更加方便吗?可以kvo有一个打点调用不能实现的方法:例如

    @interface People : NSObject
       {

               NSString *_name;

       }
       @end

    _name是people类的全局变量,这样我们就不能进行打点调用了,这时候kvc就派上用场了

      People *people=[People new];
        [people setValue:@"张三" forKey:@"name"];
        NSLog(@"%@",people.name);//张三
        NSString *name=[people valueForKey:@"name"];//得到值
        NSLog(@"%@",name);//张三

    你会发现程序居然没有报错,而且执行成功了

    @interface People : NSObject
       {

               NSString *name;

       }
       @end

    和_name同理

    但是我们调用一个不存在的key时,程序就会崩溃

    比如我们在程序外调用 [people setValue:@"张三" forKey:@"name1"];

    Terminating app due to uncaught exception 'NSUnknownKeyException', reason: '[<People 0x106f14270> setValue:forUndefinedKey:]: this class is not key value coding-compliant for the key name1.' 原因就是因为没有name1这个key值

    结果和上面一样:不管结果如果,你都会发先系统调用了属性的get方法,所以总结如下首先会调用set(get)方法如果set(get)方法不存在,会找到_key当_key不存在时,会找到key当key不存在时,会crash。

    2.kvc可以根据路径值访问属性和对属性赋值,例如

    我们有一个car类,有一个people类

    @interface People : NSObject

    @property (nonatomic,strong) NSString *name;
    @property (nonatomic,strong) NSNumber *age;

    @property (nonatomic,strong) Car *car;
    @end

    @interface Car : NSObject
    @property (nonatomic,strong) NSString *name;
    @property (nonatomic,strong) UIColor *bgColor;
    @end

    类外调用:

     People *people = [People new];

     [people setValue:@"SUV" forKeyPath:@"car.name"];

    NSString *carName=[people valueForKey:@"car.name"];//suv

    3.可以通过字典对属性赋值:

    例如:

    @interface People : NSObject

    @property (nonatomic,strong) NSString *name;
    @property (nonatomic,strong) NSNumber *age;

    @end

     NSDictionary *dict = @{@"name": @"张三",@"age":@12}

     People *people = [People new];
      [people setValuesForKeysWithDictionary:dict];

    NSLog(@"%@  %d",people.name,people.age);//张三   12

    注意事项:如果字典中的键值有id之类的xcode保留值程序就会崩溃,基本数据类行也不识别,解决方法:

    //kvc崩溃的话写以下方法
    - (void)setValue:(id)value forUndefinedKey:(NSString *)key
    {
        if ([key isEqualToString:@"id"]) {//这里的id指的是oc里面的保留字
            self.pID = value;
        }else if ([key isEqualToString:@"pSex"])
        {

    //@property (nonatomic,assign) BOOL sex;
            self.sex = [value boolValue];//把对象的值改为基本的数据类型
        }

        NSLog(@"%@ %@",value,key);
    }

     kvo:全称是Key-value observing,翻译成键值观察。提供了一种当其它对象属性被修改的时候能通知当前对象的机制。再MVC大行其道的Cocoa中,KVO机制很适合实现model和controller类之间的通讯。

    不多说:举例说明

    创建一个people类


    @interface People : NSObject
    @property (nonatomic,strong) NSString *name;
    @end

    给一个person对象添加观察者

     [_people addObserver:self forKeyPath:@"name" options:NSKeyValueObservingOptionOld|NSKeyValueObservingOptionNew context:@"hello"];//NSKeyValueObservingOptionOld,获得旧的值 NSKeyValueObservingOptionNew:获得新的值 

    假如我们改变people的name属性,就会触发事件

    /*

    此方法必须实现,不实现的话系统回报/*
    reason: '<ViewController: 0x8e06540>: An -observeValueForKeyPath:ofObject:change:context: message was received but not handled.
    错误

    */

    - (void)observeValueForKeyPath:(NSString *)keyPath ofObject:(id)object change:(NSDictionary *)change context:(void *)context
    {
    /*
     keyPath:观察的路径
     object:被观察者
     change:改变的值
     context:对应添加时的context
     */
        NSLog(@"%s",__FUNCTION__);
    }

     
     
     
  • 相关阅读:
    getParameter和getAttribute的区别
    forward和sendRedirect的区别
    关于html/css的路径问题
    手写ORM
    数据库其他使用方法介绍
    Navicat使用与python操作数据库
    表查询
    表与表之间的三种关系
    SQL语法
    MySQL数据库的安装与使用
  • 原文地址:https://www.cnblogs.com/hualuoshuijia/p/4998846.html
Copyright © 2011-2022 走看看