财经资讯网站该怎么做推广,建平县营商环境建设局网站,wordpress破解版下载,做网站公司-深圳信科OC中的一个比较有特色的知识点#xff1a;KVC和KVO一、KVC操作OC中的KVC操作就和Java中使用反射机制去访问类的private权限的变量#xff0c;很暴力的#xff0c;这样做就会破坏类的封装性#xff0c;本来类中的的private权限就是不希望外界去访问的#xff0c;但是我们这…OC中的一个比较有特色的知识点KVC和KVO一、KVC操作OC中的KVC操作就和Java中使用反射机制去访问类的private权限的变量很暴力的这样做就会破坏类的封装性本来类中的的private权限就是不希望外界去访问的但是我们这样去操作就会反其道而行但是我们有时候真的需要去这样做哎。所以说有些事不是都是顺其自然的而是需要的时候自然就诞生了。下面就来看一下这种技术的使用Dog.h[objc] view plaincopy 1. // 2. // Dog.h 3. // 42_KVC 4. // 5. // Created by jiangwei on 14-10-14. 6. // Copyright (c) 2014年 jiangwei. All rights reserved. 7. // 8. 9. #import Foundation/Foundation.h 10. 11. interface Dog : NSObject 12. 13. end Dog.m[objc] view plaincopy 1. // 2. // Dog.m 3. // 42_KVC 4. // 5. // Created by jiangwei on 14-10-14. 6. // Copyright (c) 2014年 jiangwei. All rights reserved. 7. // 8. 9. #import Dog.h 10. 11. implementation Dog 12. 13. end 定义了Dog这个类但是什么都没有他只是一个中间类没什么作用在这个demo中。Person.h[objc] view plaincopy 1. // 2. // Person.h 3. // 42_KVC 4. // 5. // Created by jiangwei on 14-10-14. 6. // Copyright (c) 2014年 jiangwei. All rights reserved. 7. // 8. 9. #import Foundation/Foundation.h 10. #import Dog.h 11. 12. interface Person : NSObject{ 13. private 14. NSString *_name; 15. NSDog *_dog; 16. 17. NSInteger *age; 18. } 19. 20. end Person.m[objc] view plaincopy 1. // 2. // Person.m 3. // 42_KVC 4. // 5. // Created by jiangwei on 14-10-14. 6. // Copyright (c) 2014年 jiangwei. All rights reserved. 7. // 8. 9. #import Person.h 10. 11. implementation Person 12. 13. - (NSString *)description{ 14. NSLog(%,_name); 15. return _name; 16. } 17. 18. end Person类中我们定义了两个属性但是这两个属性对外是不可访问的而且也没有对应的get/set方法。我们也实现了description方法用于打印结果看一下测试代码main.m[objc] view plaincopy 1. // 2. // main.m 3. // 42_KVC 4. // 5. // Created by jiangwei on 14-10-14. 6. // Copyright (c) 2014年 jiangwei. All rights reserved. 7. // 8. 9. #import Foundation/Foundation.h 10. #import Person.h 11. #import Dog.h 12. 13. //KVC很暴力及时一个类的属性是私有的而且也没有get/set方法同样可以读写 14. //相当于Java中的反射破坏类的封装性 15. int main(int argc, const charchar * argv[]) { 16. autoreleasepool { 17. 18. Person *p [[Person alloc] init]; 19. 20. //设置值 21. //这里setValue方法第一个参数是value,第二个参数是key(就是类的属性名称) 22. [p setValue:jiangwei forKey:name]; 23. 24. Dog *dog [[Dog alloc] init]; 25. [p setValue:dog forKey:dog]; 26. 27. //KVC设置值时如果属性有set方法则优先调用set方法如果没有则直接设置上去get方法类似 28. 29. //读取值 30. NSString *name [p valueForKey:name]; 31. 32. //设置基本数据类型 33. //这里需要将基本类型转化成NSNumber 34. //在设置值的时候会有自动解包的过程NSNumber会解包赋值给age 35. [p setValue:22 forKey:age]; 36. 37. NSLog(%,p); 38. 39. return 0; 40. } 41. return 0; 42. } 这里我们生成一个Person对象然后开始使用KVC技术了1、设置属性值[java] view plaincopy 1. //设置值 2. //这里setValue方法第一个参数是value,第二个参数是key(就是类的属性名称) 3. [p setValue:jiangwei forKey:name]; 4. 5. Dog *dog [[Dog alloc] init]; 6. [p setValue:dog forKey:dog]; 使用setValue方法就可以进行对属性进行设置值操作了同时需要传递这个属性的名称这个和Java中使用反射机制真的很像。注KVC设置值时如果属性有set方法则优先调用set方法如果没有则直接设置上去get方法一样[java] view plaincopy 1. //设置基本数据类型 2. //这里需要将基本类型转化成NSNumber 3. //在设置值的时候会有自动解包的过程NSNumber会解包赋值给age 4. [p setValue:22 forKey:age]; 还有一个需要注意的地方当我们在设置基本类型的时候需要将其转化成NSNumber类型的。2、取属性的值[java] view plaincopy 1. //读取值 2. NSString *name [p valueForKey:name]; 取值就简单了下面再来看一下KVC中强大的功能键值路径键值路径是对于一个类中有数组对象的属性进行便捷操作。看个场景一个作者有多本书Author.h[objc] view plaincopy 1. // 2. // Author.h 3. // 43_KeyValuePath 4. // 5. // Created by jiangwei on 14-10-15. 6. // Copyright (c) 2014年 jiangwei. All rights reserved. 7. // 8. 9. #import Foundation/Foundation.h 10. 11. interface Author : NSObject{ 12. NSString *_name; 13. 14. //作者出版的书,一个作者对应多个书籍对象 15. NSArray *_issueBook; 16. } 17. 18. end 作者类中定义了名字和一个书籍数组Author.m[objc] view plaincopy 1. // 2. // Author.m 3. // 43_KeyValuePath 4. // 5. // Created by jiangwei on 14-10-15. 6. // Copyright (c) 2014年 jiangwei. All rights reserved. 7. // 8. 9. #import Author.h 10. 11. implementation Author 12. 13. end Book.h[objc] view plaincopy 1. // 2. // Book.h 3. // 43_KeyValuePath 4. // 5. // Created by jiangwei on 14-10-15. 6. // Copyright (c) 2014年 jiangwei. All rights reserved. 7. // 8. 9. #import Foundation/Foundation.h 10. #import Author.h 11. 12. interface Book : NSObject{ 13. Author *_author; 14. } 15. 16. property NSString *name; 17. property floatfloat *price; 18. 19. end 定义了一个作者属性书的名字价格Book.m[objc] view plaincopy 1. // 2. // Book.m 3. // 43_KeyValuePath 4. // 5. // Created by jiangwei on 14-10-15. 6. // Copyright (c) 2014年 jiangwei. All rights reserved. 7. // 8. 9. #import Book.h 10. 11. implementation Book 12. 13. end 看一下测试代码main.m[objc] view plaincopy 1. // 2. // main.m 3. // 43_KeyValuePath 4. // 5. // Created by jiangwei on 14-10-15. 6. // Copyright (c) 2014年 jiangwei. All rights reserved. 7. // 8. 9. #import Foundation/Foundation.h 10. #import Book.h 11. #import Author.h 12. 13. int main(int argc, const charchar * argv[]) { 14. autoreleasepool { 15. 16. //------------------KVC键值路径 17. /* 18. Book *book [[Book alloc] init]; 19. Author *author [[Author alloc] init]; 20. 21. //设置作者 22. [book setValue:author forKey:author]; 23. 24. //设置作者的名字 25. //路径为author.name,中间用点号进行连接 26. [book setValue:jiangwei forKeyPath:author.name]; 27. NSString *name [author valueForKey:name]; 28. NSLog(name is %,name); 29. */ 30. 31. 32. //--------------------KVC的运算 33. Author *author [[Author alloc] init]; 34. [author setValue:莫言 forKeyPath:name]; 35. 36. Book *book1 [[Book alloc] init]; 37. book1.name 红高粱; 38. book1.price 9; 39. Book *book2 [[Book alloc] init]; 40. book2.name 蛙; 41. book2.price 10; 42. NSArray *array [NSArray arrayWithObjects:book1,book2, nil nil]; 43. [author setValue:array forKeyPath:issueBook]; 44. 45. //基本数据类型会自动被包装成NSNumber装到数组中 46. //得到所有书籍的价格 47. NSArray *priceArray [author valueForKeyPath:issueBook.price]; 48. NSLog(%,priceArray); 49. 50. //获取数组的大小 51. NSNumber *count [author valueForKeyPath:issueBook.count]; 52. NSLog(count%,count); 53. 54. //获取书籍价格的总和 55. NSNumber *sum [author valueForKeyPath:issueBook.sum.price]; 56. NSLog(%,sum); 57. 58. //获取书籍的平均值 59. NSNumber *avg [author valueForKeyPath:issueBook.avg.price]; 60. NSLog(%,avg); 61. 62. //获取书籍的价格最大值和最小值 63. NSNumber *max [author valueForKeyPath:issueBook.max.price]; 64. NSNumber *min [author valueForKeyPath:issueBook.min.price]; 65. 66. } 67. return 0; 68. } 1、首先通过前面说到的KVC设置作者的书籍数组[objc] view plaincopy 1. //--------------------KVC的运算 2. Author *author [[Author alloc] init]; 3. [author setValue:莫言 forKeyPath:name]; 4. 5. Book *book1 [[Book alloc] init]; 6. book1.name 红高粱; 7. book1.price 9; 8. Book *book2 [[Book alloc] init]; 9. book2.name 蛙; 10. book2.price 10; 11. NSArray *array [NSArray arrayWithObjects:book1,book2, nil nil]; 12. [author setValue:array forKeyPath:issueBook]; 添加了两本书籍2、下面就开始用到KVC中键值路径了1)获取作者类中书籍数组中所有书籍的价格[java] view plaincopy 1. //基本数据类型会自动被包装成NSNumber装到数组中 2. //得到所有书籍的价格 3. NSArray *priceArray [author valueForKeyPath:issueBook.price]; 4. NSLog(%,priceArray); 看到了issueBook.price 这就是键值路径的使用issueBook是作者类中的书籍数组属性名price是书籍类的属性中间用点号进行连接这样我们就可以获取到了所有书籍的价格了如果在Java中我们需要用一个循环操作。但是OC中多么方便。2)获取作者类中书籍数组的大小[java] view plaincopy 1. //获取数组的大小 2. NSNumber *count [author valueForKeyPath:issueBook.count]; 3. NSLog(count%,count); 使用 issueBook.count 键值路径获取书籍数组的大小issueBook是作者类中的书籍数组属性名count是特定一个写法可以把它想象成一个方法中间任然用点号进行连接3)获取作者类中书籍数组的价格总和[java] view plaincopy 1. //获取书籍价格的总和 2. NSNumber *sum [author valueForKeyPath:issueBook.sum.price]; 3. NSLog(%,sum); 使用 issueBook.sum.price 键值路径获取书籍数组中的价格总和issueBook是作者类中的书籍数组属性名sum是特性写法可以把它想象成一个方法price是书籍的价格属性名可以把它看成是sum的一个参数中间用点号进行连接如果在java中这个需要用一个循环来计算总和OC中很方便的4)获取作者类中书籍数组的价格平均值、最小值、最大值[objc] view plaincopy 1. //获取书籍的平均值 2. NSNumber *avg [author valueForKeyPath:issueBook.avg.price]; 3. NSLog(%,avg); 4. 5. //获取书籍的价格最大值和最小值 6. NSNumber *max [author valueForKeyPath:issueBook.max.price]; 7. NSNumber *min [author valueForKeyPath:issueBook.min.price]; 操作和上面类似这里就不解释了我们看到上面返回来的数据都是NSNumber类型的二、KVO操作 KVO操作在OC中也是经常会用到的而且这种机制在java中不存在的。它的作用就是用来监听类中属性值的变化实现原理是观察者模式当然我们也可以使用观察者模式在Java中实现这样的机制看一下具体的例子现在有一个小孩类他有两个属性开心值饥饿值然后还有一个护士类用来监听孩子类的这两个属性值的Chidren.h[objc] view plaincopy 1. // 2. // Children.h 3. // 44_KVO 4. // 5. // Created by jiangwei on 14-10-16. 6. // Copyright (c) 2014年 jiangwei. All rights reserved. 7. // 8. 9. #import Foundation/Foundation.h 10. 11. interface Children : NSObject 12. 13. property NSInteger *hapyValue; 14. property NSInteger *hurryValue; 15. 16. 17. end Children.m[objc] view plaincopy 1. // 2. // Children.m 3. // 44_KVO 4. // 5. // Created by jiangwei on 14-10-16. 6. // Copyright (c) 2014年 jiangwei. All rights reserved. 7. // 8. 9. #import Children.h 10. 11. implementation Children 12. 13. - (id) init{ 14. self [super init]; 15. if(self ! nil){ 16. //启动定时器 17. [NSTimer scheduledTimerWithTimeInterval:1 target:self selector:selector(timerAction) userInfo:nil repeats:YES]; 18. self.hapyValue 100; 19. } 20. return self; 21. } 22. 23. - (void) timerAction:(NSTimer *) timer{ 24. //使用set方法修改属性值才能触发KVO 25. 26. int value _hapyValue; 27. [self setHapyValue:--value]; 28. 29. int values _hurryValue; 30. [self setHurryValue:--values]; 31. } 32. 33. 34. end 在初始化方法中我们启动一个定时器然后隔1s就去修改孩子类的值Nure.h[objc] view plaincopy 1. // 2. // Nure.h 3. // 44_KVO 4. // 5. // Created by jiangwei on 14-10-16. 6. // Copyright (c) 2014年 jiangwei. All rights reserved. 7. // 8. 9. #import Foundation/Foundation.h 10. 11. class Children; 12. interface Nure : NSObject{ 13. Children *_children; 14. } 15. 16. - (id) initWithChildren:(Children *)children; 17. 18. end 定义一个孩子属性Nure.m[objc] view plaincopy 1. // 2. // Nure.m 3. // 44_KVO 4. // 5. // Created by jiangwei on 14-10-16. 6. // Copyright (c) 2014年 jiangwei. All rights reserved. 7. // 8. 9. #import Nure.h 10. #import Children.h 11. 12. implementation Nure 13. 14. - (id) initWithChildren:(Children *)children{ 15. self [super init]; 16. if(self ! nil){ 17. _children children; 18. 19. //观察小孩的hapyValue 20. //使用KVO为_children对象添加一个观察者用于观察监听hapyValue属性值是否被修改 21. [_children addObserver:self forKeyPath:hapyValue options:NSKeyValueObservingOptionNew |NSKeyValueObservingOptionOld context:context]; 22. 23. //观察小孩的hurryValue 24. [_children addObserver:self forKeyPath:hurryValue options:NSKeyValueObservingOptionNew |NSKeyValueObservingOptionOld context:context]; 25. } 26. return self; 27. } 28. 29. //触发方法 30. - (void)observeValueForKeyPath:(NSString *)keyPath ofObject:(id)object change:(NSDictionary *)change context:(voidvoid *)context{ 31. NSLog(%,change); 32. //通过打印change我们可以看到对应的key 33. 34. //通过keyPath来判断不同属性的观察者 35. if([keyPath isEqualToString:hapyValue]){ 36. //这里change中有old和new的值是因为我们在调用addObserver方法时用到了 37. //NSKeyValueObservingOptionNew | NSKeyValueObservingOptionOld想要哪一个就用哪一个 38. //[change objectForKey:old]是修改前的值 39. NSNumber *hapyValue [change objectForKey:new];//修改之后的最新值 40. 41. NSInteger *value [hapyValue integerValue]; 42. 43. if(value 90){ 44. //do something... 45. } 46. }else if([keyPath isEqualToString:hurryValue]){ 47. //这里change中有old和new的值是因为我们在调用addObserver方法时用到了 48. //NSKeyValueObservingOptionNew | NSKeyValueObservingOptionOld想要哪一个就用哪一个 49. //[change objectForKey:old]是修改前的值 50. NSNumber *hurryValue [change objectForKey:new];//修改之后的最新值 51. 52. NSInteger *value [hurryValue integerValue]; 53. 54. if(value 90){ 55. //do something... 56. } 57. } 58. 59. NSLog(%,context);//打印的就是addObserver方法的context参数 60. 61. 62. 63. //使用KVC去修改属性的值也会触发事件 64. } 65. 66. - (void)dealloc{ 67. 68. //移除观察者 69. [_children removeObserver:self forKeyPath:hapyValue]; 70. [_children removeObserver:self forKeyPath:hurryValue]; 71. 72. } 73. 74. end 看到了在这里就开始进行监听操作了下面来具体看一下如何做到监听的1、添加监听对象我们使用addObserver方法给孩子添加监听对象第一个参数监听者这里是Nure,所以可以直接传递self第二个参数监听对象的属性名第三个参数监听这个属性的状态这里可以使用|进行多种组合操作属性的新值和旧值第四个参数传递内容给监听方法[java] view plaincopy 1. //观察小孩的hapyValue 2. //使用KVO为_children对象添加一个观察者用于观察监听hapyValue属性值是否被修改 3. [_children addObserver:self forKeyPath:hapyValue options:NSKeyValueObservingOptionNew |NSKeyValueObservingOptionOld context:context]; 4. 5. //观察小孩的hurryValue 6. [_children addObserver:self forKeyPath:hurryValue options:NSKeyValueObservingOptionNew |NSKeyValueObservingOptionOld context:context]; 2、监听方法[objc] view plaincopy 1. //触发方法 2. - (void)observeValueForKeyPath:(NSString *)keyPath ofObject:(id)object change:(NSDictionary *)change context:(voidvoid *)context{ 3. NSLog(%,change); 4. //通过打印change我们可以看到对应的key 5. 6. //通过keyPath来判断不同属性的观察者 7. if([keyPath isEqualToString:hapyValue]){ 8. //这里change中有old和new的值是因为我们在调用addObserver方法时用到了 9. //NSKeyValueObservingOptionNew | NSKeyValueObservingOptionOld想要哪一个就用哪一个 10. //[change objectForKey:old]是修改前的值 11. NSNumber *hapyValue [change objectForKey:new];//修改之后的最新值 12. 13. NSInteger *value [hapyValue integerValue]; 14. 15. if(value 90){ 16. //do something... 17. } 18. }else if([keyPath isEqualToString:hurryValue]){ 19. //这里change中有old和new的值是因为我们在调用addObserver方法时用到了 20. //NSKeyValueObservingOptionNew | NSKeyValueObservingOptionOld想要哪一个就用哪一个 21. //[change objectForKey:old]是修改前的值 22. NSNumber *hurryValue [change objectForKey:new];//修改之后的最新值 23. 24. NSInteger *value [hurryValue integerValue]; 25. 26. if(value 90){ 27. //do something... 28. } 29. } 30. 31. NSLog(%,context);//打印的就是addObserver方法的context参数 32. 33. 34. 35. //使用KVC去修改属性的值也会触发事件 36. } 我们上面传递的第一个参数是监听者这个方法也是在监听者中实现的当属性值发生变化的时候这个方法会被回调这个方法的参数第一个参数键值路径第二个参数监听对象第三个参数变化的值第四个参数传递的内容我们看到代码中有一个特殊的参数第三个参数NSDirctionary类型的其实我们如果不知道是干什么的我们可以打印一下他的结果看一下很简单这里就不截图说明了我们会发现他有两个键值对key是new和old他们就是分别代表这个属性值变化的前后值同时他们的得到也和之前我们添加监听对象时设置的第三个参数有关NSKeyValueObservingOptionNew |NSKeyValueObservingOptionOld那个地方设置了几种状态这里的NSDirctionary中就会有几个键值对3、销毁方法这个并不属于KVO的内容了只是在这里用到了就顺便说一下[objc] view plaincopy 1. - (void)dealloc{ 2. 3. //移除观察者 4. [_children removeObserver:self forKeyPath:hapyValue]; 5. [_children removeObserver:self forKeyPath:hurryValue]; 6. 7. } 我们在创建一个对象的时候会调用alloc方法当对象被销毁的时候会调用dealloc这个方法这个和C中的析构函数一样Java中有垃圾回收器所以没有此类的方法但是有一个finalize方法其实这个方法就是在垃圾回收器回收对象的时候会调用和这个功能差不多但是在Java中我们并不提倡使用这个方法。因为会造成GC的回收发生错误。我们在销毁方法中需要移除监听者总结这一篇就介绍了OC中比较有特色的两个机制KVC和KVOKVC就是可以暴力的去get/set类的私有属性同时还有强大的键值路径对数组类型的属性进行操作 KVO监听类中属性值变化的转载于:https://www.cnblogs.com/GhostKZShadow/p/5105176.html