IOS KVC,KVO

作者: 小暖风 | 来源:发表于2017-08-19 17:42 被阅读34次

    KVC

    KVC是key Value Coding的缩写,主要方法有setValue:forKey和valueForKey:。

    setValue:forKey:主要是赋值。value参数是值,key参数是变量名。

    eg:[student setValue:@”张3”forKey:@”name”];

    给student的name属性赋值为张3 。

    valueForKey: 主要是取值。key是变量名,方法返回变量的值。

    setValue:forKeyPath:可以通过“.”的方式,给私有的自定义类型的私有变量赋值。

    eg:[student setValue:@”LI4” forKeyPath:@”person.name”];

    利用KVC机制,可以给继承于NSObject类的私有变量赋值。

    注意:

    key里面的属性,是什么类型,value对应的就应该是什么类型。

    key里面的属性,一定要是类的属性,否则会报错。

    主要用在多个类,对象嵌套的时候。

    譬如:

    我们有一个人 这个人有一个手机类 这个手机类 有一个电池类 我们要获取这个电池类 比之前复杂了吧。

    没有KVC

    Persion *persion =[ [Persion alloc] init ];

    Phone *phone = persion.phone;

    Battery *battery = phone.battery;

    一:使用KVC

    Battery *battery = [persion valueForKeyPath: @"phone.battery" ];

    注意- valueForKeyPath 里面的值是区分大小写的,你如果写出Phone.Battery 是不行的.

    KVC 最常用的还是在序列化和反序列话对象。我们经常需要把json字符串反序列化成我们想要的对象 下面是一个例子 将字典用NSKeyedArchiver 序列化成对象

    - (id)initWithDictionary:(NSDictionary *)dictionary {

    self = [self init];

    if (self){

    [self setValuesForKeysWithDictionary:dictionary];

    }

    return self;

    }

    注意 这里有一个坑 当我们setValue 给一个没有定义的字典值(forUndefinedKey)时 会抛出NSUndefinedKeyException异常的 记的处理此种情况.

    还有一个需要注意的是KVC 并没有类型检验,毕竟Object-C 还是动态的啦。 还是看下面的代码吧

    [persion setValue:[NSNumber numberWithInteger:1] forKey:@"name"];

    // compiles and runs

    persion.name = [NSNumber numberWithInteger:1];

    // won't compile: Incompatible pointer types assigning to 'NSString *' from 'NSNumber *'

    setValue forKey 得到的对象是泛型的id, 只有在使用的时候才能确定类型。你可能会问不至于吧 OC 这样弱啊,当然不是 OC 提供了了一个方法validateValue来解决这个问题

    @property (nonatomic, strong) NSString name;

    - (BOOL)validateName:(id*)ioValue error:(NSError**)error {

    // Validation logic goes here

    }

    Person *p = [Person new];

    NSString *name = @"Jason Hu";

    NSError *error = nil;

    // This call below actually calls our validateName: error: method

    if ([p validateValue:&name forKey:@"name" error:&error]) {

    [p setValue:name forKey:@"name"];

    }

    你可能会问写这样多代码 才只验证了一个属性 那如果我这个类有n+个属性 难道我要写n+个验证方法吗?

    二:KVC 验证

    到这里我们对KVC已经有了一个初步印象,到这里其实还只是冰山一角。

    下面我们要提高更高的要求,如果让key 支持 不区分大小写

    下面我们提到一个方法initialize

    initialize是在类或者其子类的第一个方法被调用前调用。所以如果类没有被引用进项目或者类文件被引用进来,但是没有使用,那么initialize也不会被调用 ,到这里 知道我们接下来要干嘛了吧

    + (void)initialize {

    [super initialize];

    dispatch_once(&onceToken, ^{

    modelProperties = [NSMutableDictionary dictionary];

    propertyTypesArray = @[/* removed for brevity */];

    });

    NSMutableDictionary *translateNameDict = [NSMutableDictionary dictionary];

    [self hydrateModelProperties:[self class] translateDictionary:translateNameDict];

    [modelProperties setObject:translateNameDict forKey:[self calculateClassName]];

    }

    + (void)hydrateModelProperties:(Class)class translateDictionary:(NSMutableDictionary *)translateDictionary {

    if (!class || class == [NSObject class]){

    return;

    }

    unsigned int outCount, i;

    objc_property_t *properties = class_copyPropertyList(class, &outCount);

    for (i = 0; i < outCount; i++){

    objc_property_t p = properties[i];

    const char *name = property_getName(p);

    NSString *nsName = [[NSString alloc] initWithCString:name encoding:NSUTF8StringEncoding];

    NSString *lowerCaseName = [nsName lowercaseString];

    [translateDictionary setObject:nsName forKey:lowerCaseName];

    //注意此处哦

    NSString *propertyType = [self getPropertyType:p];

    [self addValidatorForProperty:nsName type:propertyType];

    }

    free(properties);

    [self hydrateModelProperties:class_getSuperclass(class) translateDictionary:translateDictionary];

    }

    KVO

    Key-Value Observing (简写为KVO):当指定的对象的属性被修改了,允许对象接受到通知的机制。每次指定的被观察对象的属性被修改的时候,KVO都会自动的去通知相应的观察者,相当于设计模式中的观察者模式。

    KVO的优点:

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

    KVO是Key Value Observer的缩写,主要方法是addObserver:forKeyPath:options:context:和observeValueForPath:ofObject:change:context。

    addObserver:forKeyPath:options:context:注册监听事件。

    observeValueForPath:ofObject:change:context当注册的值,利用KVC发生改变的时候,就会触发这个方法。

    在最后的dealloc方法里面,要记得移除监听事件。

    补充:iOS之KVC和KVO

    一、KVC(key-value-coding)

    1、只针对类属性,设置键值对

    2、设置setValue: forKey:,即forKey只能为类属性

    3、取值valueForKey

    二、KVO(key-value-observing)被观察者的属性发生改变时,通知观察者

    1、利用KVC对类属性进行设置

    2、注册observing对象addObserver:forKeyPath:options:context:

    3、观察者类必须重写方法 observeValueForKeyPath:ofObject:change:context:

    4、应用,MVC模型中,数据库(dataModal)发生变化时,引起view改变,用这种方式实现非常方便

    相关文章

      网友评论

        本文标题:IOS KVC,KVO

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