美文网首页iOS专题
iOS基础(四) - KVC和KVO

iOS基础(四) - KVC和KVO

作者: 一剑孤城 | 来源:发表于2016-04-14 12:50 被阅读154次

    iOS观察者模式学习

    (1)KVC与KVO简介

    • KVC

    KVC(Key-value coding)是一种间接更改对象状态的方式。

    官方文档描述:

    Key-value coding is a mechanism for accessing an object’s properties indirectly, using strings to identify properties, rather than through invocation of an accessor method or accessing them directly through instance variables. In essence, key-value coding defines the patterns and method signatures that your application’s accessor methods implement.

    • KVC的作用

    通过键值的方式访问对象或者修改对象的值

    比如:NSString *name = [car valueForKey: @"name"];通过-valueForKey:获取对象,它会先查找以参数名命名(格式为-key或-isKey)的getter方法,对于上面的调用,valueForKey:会先寻找-name方法。如果没有这样的getter方法,它将会在对象内寻找名称格式为_key或key的实例变量。通过使用KVC,没有相关getter方法也能获取对象,不需要通过对象指针来直接访问实例变量。

    • KVC的优缺点

    1.KVC可以轻松处理集合类。(如:NSArray)

    2.KVC没有相关getter方法也能获取对象,不需要通过对象指针来直接访问实例变量

    3.简化代码

    4.KVC需要解析字符串,速度比较慢

    5.编译器无法进行错误检查

    • KVO

    KVO(Key-value Observing)是基于KVC的,一种监听方式,也就是所谓的观察者模式。

    官方文档描述:

    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.

    (2)KVC代码实现

    //1.setValue: forKey
    [car setValue: @"奔驰" forKey: @"name"];
    [car setValue: [NSNumber numberWithFloat: 80] forKey: @"speed"];
    [car setValue: @"黑色" forKey: @"carPaint"];
    
    //1.valueForKey
    NSString *name = [currentCar valueForKey: @"name"];
    NSNumber *speed = [currentCar valueForKey: @"speed"];
    NSString *carPaint = [currentCar valueForKey: @"carPaint"];
    
    //2.setValue:forKeyPath
    [car setValue: [NSNumber numberWithFloat: 40] forKeyPath: @"engine.horsepower"];
    self.showCarDetail.text = [self showCarDetail: car];
    
    //2.valueForKeyPath
    NSNumber *horsepower = [currentCar valueForKeyPath: @"engine.horsepower"];
    
    //3.整体操作:访问数组,如果使用某个键值来访问一个NSArray数组,它实际上会查询相应数组中的每个对象,然后将查询结果大包到另一个数组并返回,但是不能直接在建路径中索引这些数组,如:tires[0].pressure
    NSArray *pressures = [currentCar valueForKeyPath: @"tires.pressure"];
    NSLog(@"%@", pressures);
    
    //4.快速运算@count,@sum,@avg,@min,@max,@distinctUnionOfObjects
    NSNumber *count = [currentCar valueForKeyPath: @"tires.@count"];    //对左边键值返回数组操作,获取数组数量
    NSNumber *sum = [currentCar valueForKeyPath: @"tires.@sum.pressure"];    //对左边键值返回数组操作,获取每个数组里面的pressure值,求和
    NSNumber *avg = [currentCar valueForKeyPath: @"tires.@avg.pressure"];    //对左边键值返回数组操作,获取每个数组里面的pressure值,求平均值
    NSNumber *min = [currentCar valueForKeyPath: @"tires.@min.pressure"];    //对左边键值返回数组操作,获取每个数组里面的pressure值,找出最小值
    NSNumber *max = [currentCar valueForKeyPath: @"tires.@max.pressure"];    //对左边键值返回数组操作,获取每个数组里面的pressure值,找出最大值
    NSArray *tireType = [currentCar valueForKeyPath: @"tires.@distinctUnionOfObjects.pressure"];    //对左边键值返回数组操作,获取每个数组里面的pressure值,去掉重复的值,返回一个包含所有不重复值的数组
    NSLog(@"TiresCount: %@ Sum: %@, Avg: %@, Min: %@, Max: %@, TireType: %@", count, sum, avg, min, max, tireType);
    
    //5.批处理
    //字典里面不能为nil,如果返回值有nil,则KVC会自己处理,将返回[NSNull null]表示nil
    //<null>和(null)的区别:前者是[NSNull null]对象,而后者是正真的nil。
    NSArray *keys = [NSArray arrayWithObjects: @"make", @"modelYear", @"numberOfDoors", nil];
    NSDictionary *carValues = [currentCar dictionaryWithValuesForKeys: keys];
    NSLog(@"%@", carValues);
        
    //6.nil处理
    //可以自己运行一下,重写和没有重写setNilValueForKey:方法的代码
    [currentCar setValue: nil forKey: @"speed"];
    NSLog(@"carSpeed: %@", [currentCar valueForKey: @"speed"]);
        
    //7.处理未定义的值
    [currentCar setValue: [NSNumber numberWithFloat: 1500] forKey: @"mileage"];
    [currentCar setValue: [NSNull null] forKey: @"price"];
    [currentCar setValue: nil forKey: @"capacity"];
    NSLog(@"Mileage: %@ Price: %@, Capacity: %@", [currentCar valueForKey: @"mileage"], [currentCar valueForKey: @"price"], [currentCar valueForKey: @"capacity"]);
    
    //8.KVC有自动装箱的功能,当使用valueForKey时,它自动将标量值(int,float,struct...)放入NSNumber或NSValue中;当使用setValueForKey,它自动将标量值从这些对象取出。
    
    

    (3)KVO代码实现

    //应该在监听者里添加监听,而不是在被监听者里添加监听
    //在被监听者添加监听会造成循环引用的问题
    car = [[Car alloc] init];
    [car addObserver: self forKeyPath: @"carPaint" options: NSKeyValueObservingOptionNew | NSKeyValueObservingOptionOld context: nil];
    
    - (void)observeValueForKeyPath:(NSString *)keyPath ofObject:(id)object change:(NSDictionary<NSString *,id> *)change context:(void *)context {
        if ([keyPath isEqualToString: @"carPaint"]) {
            NSLog(@"%@", [change objectForKey: @"new"]);    //修改之后的值
            self.showCarDetail.text = [NSString stringWithFormat: @"车的颜色是%@", [change objectForKey: @"new"]];
        }
    }
    
    - (void)dealloc {
        //监听者应该是self,被监听者是car
        [car removeObserver: self forKeyPath: @"carPaint"];
    }
    
    

    (4)Demo展示:


    Observer.gif

    Demo下载

    相关文章

      网友评论

        本文标题:iOS基础(四) - KVC和KVO

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