您好,欢迎来到61ic! | [登录] [注册] 忘记密码 | 设为首页 帮助
 . 网站首页 . 业界新闻 . 设计中心 . 移动技术 . TI专栏 . ADI专栏 . FPGA专栏 . 代码工厂 . 官方商城 . 
 . 活动专区 . 新品快递 . 解决方案 . 前沿科技 . TI资源 . ADI资源 . FPGA资源 . 下载中心 . 产品展示 . 
加入收藏
付款方式
联系我们
您现在的位置: 61IC电子在线 >> 移动技术 >> iPhone >> 正文
  [图文]Objective-C KVO简单探索           ★★★ 【字体:
Objective-C KVO简单探索
作者:blog.sun…    文章来源:blog.sunnyxx    点击数:    更新时间:2014-6-30    

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.   
  5. @implementation Sark  
  6. @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.   
  7. // breakpoint 2  
  8. (lldb) po sark.class  
  9. Sark  
  10. (lldb) po object_getClass(sark)  
  11. NSKVONotifying_Sark  
  12.   
  13. // breakpoint 3  
  14. (lldb) po sark.class  
  15. Sark  
  16. (lldb) po object_getClass(sark)  
  17. 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.   
  8. + (NSArray *)protocols;  
  9. + (NSDictionary *)descriptionForProtocol:(Protocol *)proto;  
  10.   
  11. + (NSString *)parentClassHierarchy;  
  12. @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.   
  3. - (void)willChangeValueForKey:(NSString *)key  
  4. {  
  5.     NSLog(@"%@", NSStringFromSelector(_cmd));  
  6.     [super willChangeValueForKey:key];  
  7. }  
  8.   
  9. - (void)didChangeValueForKey:(NSString *)key  
  10. {  
  11.     NSLog(@"%@", NSStringFromSelector(_cmd));  
  12.     [super didChangeValueForKey:key];  
  13. }  
  14.   
  15. @end  
文章录入:admin    责任编辑:admin 
  • 上一篇文章:

  • 下一篇文章: 没有了
  • 发表评论】【加入收藏】【告诉好友】【打印此文】【关闭窗口
    最新热点 最新推荐 相关文章
    为什么Objective-C很难
    年度编程语言锁定Objective-…
    Objective-C学习笔记 利用协…
    Objective-C学习之路 委托用…
    Objective-C学习之路 使用Xc…
    Objective-C学习之路 使用Xc…
    Objective-C学习之路 使用Xc…
    Objective-C学习之路 委托模…
    Objective-C入门学习基础 类…
      网友评论:(只显示最新10条。评论内容只代表网友观点,与本站立场无关!)
    站长:61 湘ICP备13001086号-2