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. ADO.NET访问SQL Server调用存储过程带回参

    1,ADO.NET访问SQL Server调用存储过程带回参 2,DatabaseDesign  use northwind go --存储过程1 --插入一条商品 productname=芹菜 un ...

  2. 指针和引用的比较(P105)

    指针和引用的比较? 虽然使用引用和指针都可间接访问另一个值,但它们之间有两个重要区别. 第一个区别在于引用总是指向某个对象:定义引用时没有初始化是错误的. 第二个重要区别则是赋值行为的差异:给引用赋值 ...

  3. codeforces 691D Swaps in Permutation DFS

    这个题刚开始我以为是每个交换只能用一次,然后一共m次操作 结果这个题的意思是操作数目不限,每个交换也可以无限次 所以可以交换的两个位置连边,只要两个位置连通,就可以呼唤 然后连通块内排序就好了 #in ...

  4. hive UDAF

    java 程序 package com.ibeifeng.udaf; import org.apache.hadoop.hive.ql.exec.UDAF; import org.apache.had ...

  5. Apache:如何利用.htaccess文件对PHP网站或文件进行伪静态处理

    来源:http://www.ido321.com/1123.html 今天get了一招:利用.htaccess文件对PHP网站或文件进行伪静态处理. 一.检查服务器是否支持伪静态处理: 必 须要空间支 ...

  6. 机器学习——Logistic回归

    参考<机器学习实战> 利用Logistic回归进行分类的主要思想: 根据现有数据对分类边界线建立回归公式,以此进行分类. 分类借助的Sigmoid函数: Sigmoid函数图: Sigmo ...

  7. Windows Azure 不能ping通的解决方案

    Windows Azure 不能ping通如何解决? 为了避免Ping Flood攻击,Windows Azure不开放对外ICMP通讯协定,所以使用ping命令我们是无法ping通的.在微软资料中心 ...

  8. Designing Evolvable Web API with ASP.NET 随便读,随便记 “The Internet,the World Wide Web,and HTTP”——HTTP

    HTTP 我们将只聚焦在于与创建 Web APIs有关的部分. HTTP 是信息系统中的一个应用层协议,是Web的支柱. 其原先由 Berners-Lee, Roy Fielding 和 Henrik ...

  9. 在阿里云linux下使用SVN访问VisualSVN出错:SSL handshake failed: SSL error: Key usage violation in certificate has been detected

    Subversion clients receive the following error message when attempting to connect to VisualSVN Serve ...

  10. 对于一个网站,如何禁止直接从浏览器Web browser中访问js文件

    比如有一个网站,https://testsystem.infotest.com 在这个网站的内容文件目录下面,有一个scripts文件夹,该文件夹中有一个js文件,比如lukeTest.js文件 这样 ...