KVO(Key Value Observing),是观察者模式在Foundation中的实现。
 
KVO的原理
 
简而言之就是:
 
1、当一个object有观察者时,动态创建这个object的类的子类
2、对于每个被观察的property,重写其set方法
3、在重写的set方法中调用- willChangeValueForKey:和- didChangeValueForKey:通知观察者
4、当一个property没有观察者时,删除重写的方法
5、当没有observer观察任何一个property时,删除动态创建的子类
 
空说无凭,简单验证下。
  1. @interface Sark : NSObject
  2. @property (nonatomic, copy) NSString *name;
  3. @end
  4. @implementation Sark
  5. @end
  1. Sark *sark = [Sark new];
  2. // breakpoint 1
  3. [sark addObserver:self forKeyPath:@"name" options:NSKeyValueObservingOptionNew context:nil];
  4. // breakpoint 2
  5. sark.name = @"萨萨萨";
  6. [sark removeObserver:self forKeyPath:@"name"];
  7. // breakpoint 3
 
断住后分别使用- class和object_getClass()打出sark对象的Class和真实的Class
  1. // breakpoint 1
  2. (lldb) po sark.class
  3. Sark
  4. (lldb) po object_getClass(sark)
  5. Sark
  6. // breakpoint 2
  7. (lldb) po sark.class
  8. Sark
  9. (lldb) po object_getClass(sark)
  10. NSKVONotifying_Sark
  11. // breakpoint 3
  12. (lldb) po sark.class
  13. Sark
  14. (lldb) po object_getClass(sark)
  15. Sark
上面的结果说明,在sark对象被观察时,framework使用runtime动态创建了一个Sark类的子类NSKVONotifying_Sark,而且为了隐藏这个行为,NSKVONotifying_Sark重写了- class方法返回之前的类,就好像什么也没发生过一样。但是使用object_getClass()时就暴露了,因为这个方法返回的是这个对象的isa指针,这个指针指向的一定是个这个对象的类对象
 
然后来偷窥一下这个动态类实现的方法,这里请出一个NSObject的扩展NSObject+DLIntrospection,它封装了打印一个类的方法、属性、协议等常用调试方法,一目了然。
  1. @interface NSObject (DLIntrospection)
  2. + (NSArray *)classes;
  3. + (NSArray *)properties;
  4. + (NSArray *)instanceVariables;
  5. + (NSArray *)classMethods;
  6. + (NSArray *)instanceMethods;
  7. + (NSArray *)protocols;
  8. + (NSDictionary *)descriptionForProtocol:(Protocol *)proto;
  9. + (NSString *)parentClassHierarchy;
  10. @end
然后继续在刚才的断点处调试:
  1. // breakpoint 1
  2. (lldb) po [object_getClass(sark) instanceMethods]
  3. <__NSArrayI 0x8e9aa00>(
  4. - (void)setName:(id)arg0 ,
  5. - (void).cxx_destruct,
  6. - (id)name
  7. )
  8. // breakpoint 2
  9. (lldb) po [object_getClass(sark) instanceMethods]
  10. <__NSArrayI 0x8d55870>(
  11. - (void)setName:(id)arg0 ,
  12. - (class)class,
  13. - (void)dealloc,
  14. - (BOOL)_isKVOA
  15. )
  16. // breakpoint 3
  17. (lldb) po [object_getClass(sark) instanceMethods]
  18. <__NSArrayI 0x8e9cff0>(
  19. - (void)setName:(id)arg0 ,
  20. - (void).cxx_destruct,
  21. - (id)name
  22. )
首先就有个扎眼的- .cxx_destruct冒出来,这货是个啥?详细的探究请参考我的另一篇文章
 
大概就是说arc下这个方法在所有dealloc调用完成后负责释放所有的变量,当然这个和KVO没啥关系了,回到正题。
 
从上面breakpoint2的打印可以看出,动态类重写了4个方法:
 
1、- setName:最主要的重写方法,set值时调用通知函数
2、- class隐藏自己必备啊,返回原来类的class
3、- dealloc做清理犯罪现场工作
4、- _isKVOA这就是内部使用的标示了,判断这个类有没被KVO动态生成子类
 
接下来验证一下KVO重写set方法后是否调用了- willChangeValueForKey:和- didChangeValueForKey:
 
最直接的验证方法就是在Sark类中重写这两个方法:
  1. @implementation Sark
  2. - (void)willChangeValueForKey:(NSString *)key
  3. {
  4. NSLog(@"%@", NSStringFromSelector(_cmd));
  5. [super willChangeValueForKey:key];
  6. }
  7. - (void)didChangeValueForKey:(NSString *)key
  8. {
  9. NSLog(@"%@", NSStringFromSelector(_cmd));
  10. [super didChangeValueForKey:key];
  11. }
  12. @end
 

iOS KVO的原理的更多相关文章

  1. iOS KVO概述

    iOS KVO概述 面试中经常会被问到:什么是KVO?这个问题既然出现概率这么大,那么我们就来详细讲一讲到底什么是KVO.下次再有面试官问你的时候,你就可以娓娓道来,以彰显高逼格 概述 问:什么是KV ...

  2. iOS:KVO/KVC 的概述与使用

    iOS:KVO/KVC 的概述与使用       KVO   APP开发技术QQ群:347072638 一,概述 KVO,即:Key-Value Observing,它提供一种机制,当指定的对象的属性 ...

  3. iOS程序启动原理---iOS-Apple苹果官方文档翻译

    本系列所有开发文档翻译链接地址:iOS7开发-Apple苹果iPhone开发Xcode官方文档翻译PDF下载地址 //转载请注明出处--本文永久链接:http://www.cnblogs.com/Ch ...

  4. iOS kvo 结合 FBKVOController 的使用

    iOS kvo 结合 FBKVOController 的使用 一:FBKVOControlloer是FaceBook开源的一个 在 iOS,maxOS上使用 kvo的 开源库: 提供了block和@s ...

  5. iOS应用启动原理图解 及ARC强弱引用

    iOS应用启动原理图解(红色箭头表示strong强引用,绿色箭头代表weak若引用) 只要将UI控件拖到Storyboard里控制器的大view上,Xcode会自动将这些控件以强引用的形式加入到sel ...

  6. iOS Category实现原理 (补充)

    iOS Category实现原理 (补充) load 和 initialize load load方法会在程序启动就会调用,当装载类信息的时候就会调用. 调用顺序看一下源代码.在 objc-loadm ...

  7. iOS Category实现原理

    iOS Category实现原理 实现原理 我们不主动引入 Category 的头文件,Category 中的方法都会被添加进主类中.我们可以通过 - performSelector: 等方式 对 C ...

  8. iOS 应用签名原理&重签名

    在苹果的日常开发中,真机测试与打包等很多流程都会牵扯到各种证书,CertificateSigningRequest,p12等.但是很多相应的开发者并不理解iOS App应用签名的原理和流程.今天着重讲 ...

  9. iOS多线程编程原理及实践

    摘要:iOS开发中,开发者不仅要做好iOS的内存管理,而且如果你的iOS涉及多线程,那你也必须了解iOS编程中对多线程的限制,iOS主线程的堆栈大小为1M,其它线程均为512KB,且这个限制开发者是无 ...

随机推荐

  1. 服务管理,Dll查看

    //枚举系统进程 VOID CManageProcessDlg::ShowProcess() {           m_ListProcess.DeleteAllItems();      HAND ...

  2. IDEA操作GIT说明

    公司的代码库从TFS升级到了GIT,我们的自动化测试代码就需要迁移到git上.操作如下: 1.安装GIT 安装完成后,在IDEA中配置git安装路径   2.在本地磁盘新建一个空目录,例如:D:\Wo ...

  3. Discuz X1.5 利用添加好友处存储xss进行蠕虫worm扩散

    Discuz X1.5 在添加好友的地方有处存储xss,借助此处xss跟用户交互可以进行蠕虫指数扩散. 位置在添加好友处 x完之后的效果 点击后触发 ok 借助此存储xss,我们进行worm传播,dz ...

  4. WPF之UseLayoutRounding和SnapsToDevicePixels

    最近在工作中看别的朋友XML代码时,发现SnapsToDevicePixels 属性然后通过查询资料了解其作用 1)UserLayoutRounding为False,导致控件布局相对屏幕若不是整数则不 ...

  5. Oracle数据库的创建、数据导入导出

    如何结合Sql脚本和PL/SQL Developer工具来实现创建表空间.创建数据库.备份数据库.还原数据库等操作,然后实现Oracle对象创建.导入数据等操作,方便我们快速了解.创建所需要的部署Sq ...

  6. c 指针兼容性问题

    指针兼容性问题: const指针不能赋值给非const指针. 非const指针可以赋值给const 指针,但前提是只是一层间接运算 Example: int *pt1; const *pt2; con ...

  7. postgreSQL数据库(索引、视图)

    索引的含义与特点 索引是一个单独的.存储在磁盘上的数据库结构,它们包含对数据所有记录的引用指针,postgresql列类型都可以被索引,对相关列索引是提高查询操作效率的最佳途径.例如,查询select ...

  8. centos crontab 定时任务详解

    安装crontab: yum install crontabs 说明: /sbin/service crond start //启动服务 /sbin/service crond stop //关闭服务 ...

  9. C# 实现Oracle中的数据与Excel之间的转换

    最近项目要求实现数据库之间数据在各个数据库之间导入导出,在此做个笔记 1. 将Oracle中的表导入到Excel中,反之亦然  private static readonly string conne ...

  10. UML 小结(5)- 图解 Rational Rose 的详细安装过程

    在学习UML的时候,会用到画图工具:Rotional Rose . 原以为这款软件直接下载下来或者跟朋友那边拷过来就可以直接用了,结果却是没有那么简单,如果读者您也是为了解决这个家伙的安装问题的话,那 ...