KVO与KVC详解

由于ObjC主要基于Smalltalk进行设计,因此它有很多类似于Ruby、Python的动态特性,例如动态类型、动态加载、动态绑定等。今天我们着重介绍ObjC中的键值编码(KVC)、键值监听(KVO)特性:

  1. 键值编码KVC
  2. 键值监听KVO

键值编码KVC

我们知道在C#中可以通过反射读写一个对象的属性,有时候这种方式特别方便,因为你可以利用字符串的方式去动态控制一个对象。其实由于ObjC的语言特性,你根部不必进行任何操作就可以进行属性的动态读写,这种方式就是Key Value Coding(简称KVC)。

KVC的操作方法由NSKeyValueCoding协议提供,而NSObject就实现了这个协议,也就是说ObjC中几乎所有的对象都支持KVC操作,常用的KVC操作方法如下:

  • 动态设置: setValue:属性值 forKey:属性名(用于简单路径)、setValue:属性值 forKeyPath:属性路径(用于复合路径,例如Person有一个Account类型的属性,那么person.account就是一个复合属性)
  • 动态读取: valueForKey:属性名 valueForKeyPath:属性名(用于复合路径)

键值监听KVO

我们知道在WPF、Silverlight中都有一种双向绑定机制,如果数据模型修改了之后会立即反映到UI视图上,类似的还有如今比较流行的基于MVVM设计模式的前端框架,例如Knockout.js。其实在ObjC中原生就支持这种机制,它叫做Key Value Observing(简称KVO)。KVO其实是一种观察者模式,利用它可以很容易实现视图组件和数据模型的分离,当数据模型的属性值改变之后作为监听器的视图组件就会被激发,激发时就会回调监听器自身。在ObjC中要实现KVO则必须实现NSKeyValueObServing协议,不过幸运的是NSObject已经实现了该协议,因此几乎所有的ObjC对象都可以使用KVO。

在ObjC中使用KVO操作常用的方法如下:

  • 注册指定Key路径的监听器: addObserver: forKeyPath: options:  context:
  • 删除指定Key路径的监听器: removeObserver: forKeyPathremoveObserver: forKeyPath: context:
  • 回调监听: observeValueForKeyPath: ofObject: change: context:

KVO的使用步骤也比较简单:

  1. 通过addObserver: forKeyPath: options: context:为被监听对象(它通常是数据模型)注册监听器
  2. 重写监听器的observeValueForKeyPath: ofObject: change: context:方法

/*********************************KVC/KVO*******************************************/

KVC

kvc在实际开发中使用最多的地方一般有两个

  • 字典转模型:但是这个有一个局限性,如果他的属性也是一个模型的时候不能使用这个方法,或者不能一一对应的时候
  • 通过属性键设置对应属性的值

字典转模型:

 #pragma mark 简单字典转模型
         NSDictionary *dict = @{
                                @"name"  : @"jack",
                                @"money" : @"20.7",
                                };

         [p setValuesForKeysWithDictionary:dict];
         NSLog(@"name = %@, money = %f", p.name, p.money);

 #pragma mark 复杂模型
     NSDictionary *dict = @{
                            @"name"  : @"jack",
                            @"money" : @"20.7",
                            @"dog" : @{
                                    @"name" : @"wangcai",
                                    @"price" : @"10.8"
                                    },
                            @"books" : @[
                                    @{
                                        @"name" : @"5分钟突破iOS开发",
                                        @"price" : @"19.8"
                                        },
                                    @{
                                        @"name" : @"3分钟突破iOS开发",
                                        @"price" : @"24.8"
                                        },
                                    @{
                                        @"name" : @"1分钟突破iOS开发",
                                        @"price" : @"29.8"
                                        }
                                    ]
                            };
     [p setValuesForKeysWithDictionary:dict];
     NSLog(@"%@", p);
 }

设置属性的值:

 #pragma mark 单个值
         p.name = @"lnj";
         p.money = 99.8;

         [p setValue:@"lnj" forKey:@"name"];
         [p setValue:@(99.8) forKey:@"money"];
         NSLog(@"name = %@, money = %f", p.name, p.money);

 #pragma mark 多层赋值

         p.dog = [XMGDog new];
         p.dog.name = @"wangcai";
         p.dog.price = ;

         [p.dog setValue:@"wangcai" forKey:@"name"];
         [p.dog setValue:@() forKey:@"price"];

         [p setValue:@"wangcai" forKeyPath:@"dog.name"];
         [p setValue:@() forKeyPath:@"dog.price"];
         NSLog(@"name = %@, price = %f", p.dog.name, p.dog.price);

 #pragma mark 私有属性

         [p setValue:@"lnj" forKeyPath:@"_name"];
         [p setValue:@() forKeyPath:@"_age"];

         NSLog(@"name = %@", p.name);
         [p say];

KVO

1:创建一个对象

iCocos *stu =

2:注册指定Key路径的监听器,并且修改相应的属性

 [stu addObserver:self forKeyPath:@"score" options:NSKeyValueObservingOptionNew | NSKeyValueObservingOptionOld context:nil];

     stu.score = ;

     stu.score = ;

3:删除指定Key路径的监听器

 #warning 注意只有调用set方法修改才能监听到 \
 内部实现原理是: 系统会自动给我们生成一个子类, 然后重写子类的set方法, 在set方法中通知监听
     stu->_score = ;
     [stu removeObserver:self forKeyPath:@"score"];

4:回调监听

 - (void)observeValueForKeyPath:(nullable NSString *)keyPath ofObject:(nullable id)object change:(nullable NSDictionary *)change context:(nullable void *)context
 {
     NSLog(@"keyPath = %@, obj = %@, change = %@, context = %@", keyPath, object, change, context);
 }

KVO内部实现机制:

系统会自动给我们生成一个子类, 然后重写子类的set方法, 在set方法中通知监听

iOS开发——实用篇&KVO与KVC详解的更多相关文章

  1. iOS开发支付篇——内购(IAP)详解

    1 <em>内购所需要的资料整理总结,史上最完整的,哈哈哈哈哈哈</em> 思维导图 重点总结: 1 2 3 4 5 6 7 8 9 10 11 12 13 1.获取内购列表( ...

  2. iOS开发——实用篇&提高iOS开发效率的方法和工具

    提高iOS开发效率的方法和工具 介绍 这篇文章主要是介绍一下我在iOS开发中使用到的一些可以提升开发效率的方法和工具. IDE 首先要说的肯定是IDE了,说到IDE,Xcode不能跑,当然你也可能同时 ...

  3. iOS开发 - OC - block的详解 - 基础篇

    深入理解oc中的block 苹果在Mac OS X10.6 和iOS 4之后引入了block语法.这一举动对于许多OC使用者的编码风格改变很大.就我本人而言,感觉block用起来还是很爽的,但一直以来 ...

  4. iOS 开发之 -- UDID和UUID的详解

    老实说,搞了几年的ios开发了,对基础的概念,还是不牢固,整天都是为了赶进度而码代码,这里记录一下这两者的区别: UDID的全名为 Unique Device Identifier :设备唯一标识符. ...

  5. iOS开发——高级技术&本地化与国际化详解

    本地化与国际化详解 效果如下:   英语:                                                                    中文: 具体实现如下: ...

  6. 【iOS 开发】基本 UI 控件详解 (UIButton | UITextField | UITextView | UISwitch)

    博客地址 : http://blog.csdn.net/shulianghan/article/details/50051499 ; 一. UI 控件简介 1. UI 控件分类 UI 控件分类 : 活 ...

  7. iOS开发——实用篇Swift篇&项目开发常用实用技术

    项目开发常用实用技术 实现拨打电话 要实现打电话功能,最简单最直接的方式便是:直接跳到拨号界面 (注意:这个需要真机调试,模拟器无效果)     UIApplication.sharedApplica ...

  8. iOS开发 - OC - block的详解 - 深入篇

    深入理解oc中的block 苹果在Mac OS X10.6 和iOS 4之后引入了block语法.这一举动对于许多OC使用者的编码风格改变很大.就我本人而言,感觉block用起来还是很爽的,但一直以来 ...

  9. iOS开发——实用篇Swift篇&QQ登入界面实现

    QQ登入界面实现 我们知道在App Store中几乎所有软件都设计到账户的登入,而我们最常见的就是QQ,微信,在没有踏入程序员这条不归路之前,看到一个个的界面都感觉好高大上的样子. 在学习的过程中,自 ...

随机推荐

  1. [Everyday Mathematics]20150203

    设 $f$ 在 $\bbR$ 上连续可导, 且 $\dps{f'\sex{\frac{1}{2}}=0}$. 试证: $$\bex \exists\ \xi\in \sex{0,\frac{1}{2} ...

  2. java web 学习九(通过servlet生成验证码图片)

    一.BufferedImage类介绍 生成验证码图片主要用到了一个BufferedImage类,如下:

  3. Devexpress DateEdit选年月 z

    Mask与Display只显示年月2012-02这种格式,但用户选择起来还是不爽,体验太差. 效果如下: 代码: using Microsoft.VisualBasic; using System; ...

  4. 总结c++ primer中的notes

    转载:http://blog.csdn.net/ace_fei/article/details/7386517 说明: C++ Primer, Fourth Edition (中英文)下载地址:htt ...

  5. sql基本语句

    ---恢复内容开始--- 查询有几个不同的职位名称: select distinct name from a: group by: 现在有两个表product和sales,字段分别如下: TABLES ...

  6. 限制su权限

    1.  修改用户的组为wheel组 2.  修改PAM配置文件 修改PAM的配置文件,使得只有属于wheel组的用户才能使用su命令 去掉此处的注释即可: 3.  测试 当不属于wheel组的时候,即 ...

  7. 《Genesis-3D开源游戏引擎完整实例教程-2D射击游戏篇05:角色中弹》

    5.角色中弹 概述: 为了使游戏具有挑战性,大部分游戏设定中,游戏角色都有生命限制.即在游戏中,由于玩家的操控操控不当,导致游戏角色死亡游戏终止.打飞机游戏也不例外,当敌人击中角色的时候,角色宣判死亡 ...

  8. 【转】linux shell 正则表达式(BREs,EREs,PREs)差异比较

    我想各位也和我一样,再linux下使用grep,egrep, awk , sed, vi的搜索时,会经常搞不太清楚,哪此特殊字符得使用转义字符'\' ..   哪些不需要, grep与egrep的差异 ...

  9. 产品经理如何赢得开发人员的尊重和支持?-摘自infoq

    对于产品经理来说,赢得开发人员的尊重和支持,从某种意义上讲,是产品迈向成功的坚实一步.最近,知乎社区上的开发人员和管理者在前.后两个帖子中对此展开了激烈的讨论,其中不乏真知灼见. 林志霖Cray认为产 ...

  10. work3

    HOMEWORK-03 红字部分为组员修改的意见 文件介绍 在EXE文件夹中的main.exe文件为本项目执行文件直接点击即可,CODE文件夹中的C文件夹中包含了算法部分的代码,其编译出的DLL文件在 ...