KVC和KVO
OC中的一個(gè)比較有特色的知識(shí)點(diǎn):KVC和KVO
一、KVC操作
OC中的KVC操作就和Java中使用反射機(jī)制去訪問(wèn)類的private權(quán)限的變量,很暴力的,這樣做就會(huì)破壞類的封裝性,本來(lái)類中的的private權(quán)限就是不希望外界去訪問(wèn)的,但是我們這樣去操作,就會(huì)反其道而行,但是我們有時(shí)候真的需要去這樣做,哎。所以說(shuō)有些事不是都是順其自然的,而是需要的時(shí)候自然就誕生了。
下面就來(lái)看一下這種技術(shù)的使用:
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這個(gè)類,但是什么都沒(méi)有,他只是一個(gè)中間類,沒(méi)什么作用,在這個(gè)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類中我們定義了兩個(gè)屬性,但是這兩個(gè)屬性對(duì)外是不可訪問(wèn)的,而且也沒(méi)有對(duì)應(yīng)的get/set方法。我們也實(shí)現(xiàn)了description方法,用于打印結(jié)果
看一下測(cè)試代碼
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:很暴力,及時(shí)一個(gè)類的屬性是私有的,而且也沒(méi)有g(shù)et/set方法,同樣可以讀寫??
14. //相當(dāng)于Java中的反射,破壞類的封裝性??
15. int?main(int?argc,?const?charchar?*?argv[])?{??
16. ????@autoreleasepool?{??
17. ??????????
18. ????????Person?*p?=?[[Person?alloc]?init];??
19. ??????????
20. ????????//設(shè)置值??
21. ????????//這里setValue方法:第一個(gè)參數(shù)是value,第二個(gè)參數(shù)是key(就是類的屬性名稱)??
22. ????????[p?setValue:@"jiangwei"?forKey:@"name"];??
23. ??????????
24. ????????Dog?*dog?=?[[Dog?alloc]?init];??
25. ????????[p?setValue:dog?forKey:@"dog"];??
26. ??????????
27. ????????//KVC設(shè)置值時(shí),如果屬性有set方法,則優(yōu)先調(diào)用set方法,如果沒(méi)有則直接設(shè)置上去,get方法類似??
28. ??????????
29. ????????//讀取值??
30. ????????NSString?*name?=?[p?valueForKey:@"name"];??
31. ??????????
32. ????????//設(shè)置基本數(shù)據(jù)類型??
33. ????????//這里需要將基本類型轉(zhuǎn)化成NSNumber??
34. ????????//在設(shè)置值的時(shí)候,會(huì)有自動(dòng)解包的過(guò)程,NSNumber會(huì)解包賦值給age??
35. ????????[p?setValue:@22?forKey:@"age"];??
36. ??????????
37. ????????NSLog(@"%@",p);??
38. ??????????
39. ????????return?0;??
40. ????}??
41. ????return?0;??
42. }??
這里我們生成一個(gè)Person對(duì)象,然后開(kāi)始使用KVC技術(shù)了:
1、設(shè)置屬性值
[java]??view plaincopy
1. //設(shè)置值??
2. //這里setValue方法:第一個(gè)參數(shù)是value,第二個(gè)參數(shù)是key(就是類的屬性名稱)??
3. [p?setValue:@"jiangwei"?forKey:@"name"];??
4. ??????????
5. Dog?*dog?=?[[Dog?alloc]?init];??
6. [p?setValue:dog?forKey:@"dog"];??
使用setValue方法,就可以進(jìn)行對(duì)屬性進(jìn)行設(shè)置值操作了,同時(shí)需要傳遞這個(gè)屬性的名稱,這個(gè)和Java中使用反射機(jī)制真的很像。
注:KVC設(shè)置值時(shí),如果屬性有set方法,則優(yōu)先調(diào)用set方法,如果沒(méi)有則直接設(shè)置上去,get方法一樣
[java]??view plaincopy
1. //設(shè)置基本數(shù)據(jù)類型??
2. //這里需要將基本類型轉(zhuǎn)化成NSNumber??
3. //在設(shè)置值的時(shí)候,會(huì)有自動(dòng)解包的過(guò)程,NSNumber會(huì)解包賦值給age??
4. [p?setValue:@22?forKey:@"age"];??
還有一個(gè)需要注意的地方:當(dāng)我們?cè)谠O(shè)置基本類型的時(shí)候,需要將其轉(zhuǎn)化成NSNumber類型的。
2、取屬性的值
[java]??view plaincopy
1. //讀取值??
2. NSString?*name?=?[p?valueForKey:@"name"];??
取值就簡(jiǎn)單了
下面再來(lái)看一下KVC中強(qiáng)大的功能:鍵值路徑
鍵值路徑是對(duì)于一個(gè)類中有數(shù)組對(duì)象的屬性進(jìn)行便捷操作。
看個(gè)場(chǎng)景:
一個(gè)作者有多本書
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. ????//作者出版的書,一個(gè)作者對(duì)應(yīng)多個(gè)書籍對(duì)象??
15. ????NSArray?*_issueBook;??
16. }??
17. ??
18. @end??
作者類中定義了名字和一個(gè)書籍?dāng)?shù)組
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??
定義了一個(gè)作者屬性,書的名字,價(jià)格
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??
看一下測(cè)試代碼
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. ????????//設(shè)置作者?
22. ????????[book?setValue:author?forKey:@"author"];?
23. ?????????
24. ????????//設(shè)置作者的名字?
25. ????????//路徑為:author.name,中間用點(diǎn)號(hào)進(jìn)行連接?
26. ????????[book?setValue:@"jiangwei"?forKeyPath:@"author.name"];?
27. ????????NSString?*name?=?[author?valueForKey:@"name"];?
28. ????????NSLog(@"name?is?%@",name);?
29. ?????????*/??
30. ??????????
31. ??????????
32. ????????//--------------------KVC的運(yùn)算??
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. ????????//基本數(shù)據(jù)類型會(huì)自動(dòng)被包裝成NSNumber,裝到數(shù)組中??
46. ????????//得到所有書籍的價(jià)格??
47. ????????NSArray?*priceArray?=?[author?valueForKeyPath:@"issueBook.price"];??
48. ????????NSLog(@"%@",priceArray);??
49. ??????????
50. ????????//獲取數(shù)組的大小??
51. ????????NSNumber?*count?=?[author?valueForKeyPath:@"issueBook.@count"];??
52. ????????NSLog(@"count=%@",count);??
53. ??????????
54. ????????//獲取書籍價(jià)格的總和??
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. ????????//獲取書籍的價(jià)格最大值和最小值??
63. ????????NSNumber?*max?=?[author?valueForKeyPath:@"issueBook.@max.price"];??
64. ????????NSNumber?*min?=?[author?valueForKeyPath:@"issueBook.@min.price"];??
65. ??????????
66. ????}??
67. ????return?0;??
68. }??
1、首先通過(guò)前面說(shuō)到的KVC設(shè)置作者的書籍?dāng)?shù)組
[objc]??view plaincopy
1. //--------------------KVC的運(yùn)算??
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、下面就開(kāi)始用到KVC中鍵值路徑了
1)獲取作者類中書籍?dāng)?shù)組中所有書籍的價(jià)格
[java]??view plaincopy
1. //基本數(shù)據(jù)類型會(huì)自動(dòng)被包裝成NSNumber,裝到數(shù)組中??
2. //得到所有書籍的價(jià)格??
3. NSArray?*priceArray?=?[author?valueForKeyPath:@"issueBook.price"];??
4. NSLog(@"%@",priceArray);??
看到了:@"issueBook.price" 這就是鍵值路徑的使用,issueBook是作者類中的書籍?dāng)?shù)組屬性名,price是書籍類的屬性,中間用點(diǎn)號(hào)進(jìn)行連接,這樣我們就可以獲取到了所有書籍的價(jià)格了,如果在Java中,我們需要用一個(gè)循環(huán)操作。但是OC中多么方便。
2)獲取作者類中書籍?dāng)?shù)組的大小
[java]??view plaincopy
1. //獲取數(shù)組的大小??
2. NSNumber?*count?=?[author?valueForKeyPath:@"issueBook.@count"];??
3. NSLog(@"count=%@",count);??
使用 @"issueBook.@count" 鍵值路徑獲取書籍?dāng)?shù)組的大小,issueBook是作者類中的書籍?dāng)?shù)組屬性名,@count是特定一個(gè)寫法,可以把它想象成一個(gè)方法,中間任然用點(diǎn)號(hào)進(jìn)行連接
3)獲取作者類中書籍?dāng)?shù)組的價(jià)格總和
[java]??view plaincopy
1. //獲取書籍價(jià)格的總和??
2. NSNumber?*sum?=?[author?valueForKeyPath:@"issueBook.@sum.price"];??
3. NSLog(@"%@",sum);??
使用 @"issueBook.@sum.price" 鍵值路徑獲取書籍?dāng)?shù)組中的價(jià)格總和,issueBook是作者類中的書籍?dāng)?shù)組屬性名,@sum是特性寫法,可以把它想象成一個(gè)方法,price是書籍的價(jià)格屬性名,可以把它看成是@sum的一個(gè)參數(shù),中間用點(diǎn)號(hào)進(jìn)行連接
如果在java中,這個(gè)需要用一個(gè)循環(huán)來(lái)計(jì)算總和,OC中很方便的
4)獲取作者類中書籍?dāng)?shù)組的價(jià)格平均值、最小值、最大值
[objc]??view plaincopy
1. //獲取書籍的平均值??
2. NSNumber?*avg?=?[author?valueForKeyPath:@"issueBook.@avg.price"];??
3. NSLog(@"%@",avg);??
4. ??
5. //獲取書籍的價(jià)格最大值和最小值??
6. NSNumber?*max?=?[author?valueForKeyPath:@"issueBook.@max.price"];??
7. NSNumber?*min?=?[author?valueForKeyPath:@"issueBook.@min.price"];??
操作和上面類似,這里就不解釋了
我們看到上面返回來(lái)的數(shù)據(jù)都是NSNumber類型的
二、KVO操作
KVO操作在OC中也是經(jīng)常會(huì)用到的,而且這種機(jī)制在java中不存在的。
它的作用就是用來(lái)監(jiān)聽(tīng)類中屬性值的變化,實(shí)現(xiàn)原理是觀察者模式,當(dāng)然我們也可以使用觀察者模式在Java中實(shí)現(xiàn)這樣的機(jī)制
看一下具體的例子:現(xiàn)在有一個(gè)小孩類,他有兩個(gè)屬性:開(kāi)心值,饑餓值,然后還有一個(gè)護(hù)士類,用來(lái)監(jiān)聽(tīng)孩子類的這兩個(gè)屬性值的
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. ????????//啟動(dòng)定時(shí)器??
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方法修改屬性值,才能觸發(fā)KVO??
25. ??????
26. ????int?value?=?_hapyValue;??
27. ????[self?setHapyValue:--value];??
28. ??????
29. ????int?values?=?_hurryValue;??
30. ????[self?setHurryValue:--values];??
31. }??
32. ??
33. ??
34. @end??
在初始化方法中,我們啟動(dòng)一個(gè)定時(shí)器,然后隔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??
定義一個(gè)孩子屬性
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為_(kāi)children對(duì)象添加一個(gè)觀察者,用于觀察監(jiān)聽(tīng)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. //觸發(fā)方法??
30. -?(void)observeValueForKeyPath:(NSString?*)keyPath?ofObject:(id)object?change:(NSDictionary?*)change?context:(voidvoid?*)context{??
31. ????NSLog(@"%@",change);??
32. ????//通過(guò)打印change,我們可以看到對(duì)應(yīng)的key??
33. ??????
34. ????//通過(guò)keyPath來(lái)判斷不同屬性的觀察者??
35. ????if([keyPath?isEqualToString:@"hapyValue"]){??
36. ????????//這里change中有old和new的值是因?yàn)槲覀冊(cè)谡{(diào)用addObserver方法時(shí),用到了??
37. ????????//NSKeyValueObservingOptionNew?|?NSKeyValueObservingOptionOld;想要哪一個(gè)就用哪一個(gè)??
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的值是因?yàn)槲覀冊(cè)谡{(diào)用addObserver方法時(shí),用到了??
48. ????????//NSKeyValueObservingOptionNew?|?NSKeyValueObservingOptionOld;想要哪一個(gè)就用哪一個(gè)??
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參數(shù)??
60. ??????
61. ??????
62. ??????
63. ????//使用KVC去修改屬性的值,也會(huì)觸發(fā)事件??
64. }??
65. ??
66. -?(void)dealloc{??
67. ??????
68. ????//移除觀察者??
69. ????[_children?removeObserver:self?forKeyPath:@"hapyValue"];??
70. ????[_children?removeObserver:self?forKeyPath:@"hurryValue"];??
71. ??????
72. }??
73. ??
74. @end??
看到了在這里就開(kāi)始進(jìn)行監(jiān)聽(tīng)操作了
下面來(lái)具體看一下如何做到監(jiān)聽(tīng)的
1、添加監(jiān)聽(tīng)對(duì)象
我們使用addObserver方法給孩子添加監(jiān)聽(tīng)對(duì)象
第一個(gè)參數(shù):監(jiān)聽(tīng)者,這里是Nure,所以可以直接傳遞self
第二個(gè)參數(shù):監(jiān)聽(tīng)對(duì)象的屬性名
第三個(gè)參數(shù):監(jiān)聽(tīng)這個(gè)屬性的狀態(tài):這里可以使用|進(jìn)行多種組合操作,屬性的新值和舊值
第四個(gè)參數(shù):傳遞內(nèi)容給監(jiān)聽(tīng)方法
[java]??view plaincopy
1. //觀察小孩的hapyValue??
2. //使用KVO為_(kāi)children對(duì)象添加一個(gè)觀察者,用于觀察監(jiān)聽(tīng)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、監(jiān)聽(tīng)方法
[objc]??view plaincopy
1. //觸發(fā)方法??
2. -?(void)observeValueForKeyPath:(NSString?*)keyPath?ofObject:(id)object?change:(NSDictionary?*)change?context:(voidvoid?*)context{??
3. ????NSLog(@"%@",change);??
4. ????//通過(guò)打印change,我們可以看到對(duì)應(yīng)的key??
5. ??????
6. ????//通過(guò)keyPath來(lái)判斷不同屬性的觀察者??
7. ????if([keyPath?isEqualToString:@"hapyValue"]){??
8. ????????//這里change中有old和new的值是因?yàn)槲覀冊(cè)谡{(diào)用addObserver方法時(shí),用到了??
9. ????????//NSKeyValueObservingOptionNew?|?NSKeyValueObservingOptionOld;想要哪一個(gè)就用哪一個(gè)??
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的值是因?yàn)槲覀冊(cè)谡{(diào)用addObserver方法時(shí),用到了??
20. ????????//NSKeyValueObservingOptionNew?|?NSKeyValueObservingOptionOld;想要哪一個(gè)就用哪一個(gè)??
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參數(shù)??
32. ??????
33. ??????
34. ??????
35. ????//使用KVC去修改屬性的值,也會(huì)觸發(fā)事件??
36. }??
我們上面?zhèn)鬟f的第一個(gè)參數(shù)是監(jiān)聽(tīng)者,這個(gè)方法也是在監(jiān)聽(tīng)者中實(shí)現(xiàn)的,當(dāng)屬性值發(fā)生變化的時(shí)候,這個(gè)方法會(huì)被回調(diào)
這個(gè)方法的參數(shù):
第一個(gè)參數(shù):鍵值路徑
第二個(gè)參數(shù):監(jiān)聽(tīng)對(duì)象
第三個(gè)參數(shù):變化的值
第四個(gè)參數(shù):傳遞的內(nèi)容
我們看到代碼中有一個(gè)特殊的參數(shù):第三個(gè)參數(shù):NSDirctionary類型的
其實(shí)我們?nèi)绻恢朗歉墒裁吹?#xff0c;我們可以打印一下他的結(jié)果看一下,很簡(jiǎn)單,這里就不截圖說(shuō)明了
我們會(huì)發(fā)現(xiàn)他有兩個(gè)鍵值對(duì)
key是:new和old
他們就是分別代表這個(gè)屬性值變化的前后值,同時(shí)他們的得到也和之前我們添加監(jiān)聽(tīng)對(duì)象時(shí)設(shè)置的第三個(gè)參數(shù)有關(guān):
NSKeyValueObservingOptionNew?|NSKeyValueObservingOptionOld
那個(gè)地方設(shè)置了幾種狀態(tài),這里的NSDirctionary中就會(huì)有幾個(gè)鍵值對(duì)
3、銷毀方法
這個(gè)并不屬于KVO的內(nèi)容了,只是在這里用到了就順便說(shuō)一下
[objc]??view plaincopy
1. -?(void)dealloc{??
2. ??????
3. ????//移除觀察者??
4. ????[_children?removeObserver:self?forKeyPath:@"hapyValue"];??
5. ????[_children?removeObserver:self?forKeyPath:@"hurryValue"];??
6. ??????
7. }??
我們?cè)趧?chuàng)建一個(gè)對(duì)象的時(shí)候會(huì)調(diào)用alloc方法,當(dāng)對(duì)象被銷毀的時(shí)候會(huì)調(diào)用dealloc這個(gè)方法,這個(gè)和C++中的析構(gòu)函數(shù)一樣,Java中有垃圾回收器,所以沒(méi)有此類的方法,但是有一個(gè)finalize方法,其實(shí)這個(gè)方法就是在垃圾回收器回收對(duì)象的時(shí)候會(huì)調(diào)用,和這個(gè)功能差不多,但是在Java中,我們并不提倡使用這個(gè)方法。因?yàn)闀?huì)造成GC的回收發(fā)生錯(cuò)誤。
我們?cè)阡N毀方法中需要移除監(jiān)聽(tīng)者
總結(jié)
這一篇就介紹了OC中比較有特色的兩個(gè)機(jī)制:KVC和KVO
KVC:就是可以暴力的去get/set類的私有屬性,同時(shí)還有強(qiáng)大的鍵值路徑對(duì)數(shù)組類型的屬性進(jìn)行操作 KVO:監(jiān)聽(tīng)類中屬性值變化的
一、KVC操作
OC中的KVC操作就和Java中使用反射機(jī)制去訪問(wèn)類的private權(quán)限的變量,很暴力的,這樣做就會(huì)破壞類的封裝性,本來(lái)類中的的private權(quán)限就是不希望外界去訪問(wèn)的,但是我們這樣去操作,就會(huì)反其道而行,但是我們有時(shí)候真的需要去這樣做,哎。所以說(shuō)有些事不是都是順其自然的,而是需要的時(shí)候自然就誕生了。
下面就來(lái)看一下這種技術(shù)的使用:
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這個(gè)類,但是什么都沒(méi)有,他只是一個(gè)中間類,沒(méi)什么作用,在這個(gè)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類中我們定義了兩個(gè)屬性,但是這兩個(gè)屬性對(duì)外是不可訪問(wèn)的,而且也沒(méi)有對(duì)應(yīng)的get/set方法。我們也實(shí)現(xiàn)了description方法,用于打印結(jié)果
看一下測(cè)試代碼
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:很暴力,及時(shí)一個(gè)類的屬性是私有的,而且也沒(méi)有g(shù)et/set方法,同樣可以讀寫??
14. //相當(dāng)于Java中的反射,破壞類的封裝性??
15. int?main(int?argc,?const?charchar?*?argv[])?{??
16. ????@autoreleasepool?{??
17. ??????????
18. ????????Person?*p?=?[[Person?alloc]?init];??
19. ??????????
20. ????????//設(shè)置值??
21. ????????//這里setValue方法:第一個(gè)參數(shù)是value,第二個(gè)參數(shù)是key(就是類的屬性名稱)??
22. ????????[p?setValue:@"jiangwei"?forKey:@"name"];??
23. ??????????
24. ????????Dog?*dog?=?[[Dog?alloc]?init];??
25. ????????[p?setValue:dog?forKey:@"dog"];??
26. ??????????
27. ????????//KVC設(shè)置值時(shí),如果屬性有set方法,則優(yōu)先調(diào)用set方法,如果沒(méi)有則直接設(shè)置上去,get方法類似??
28. ??????????
29. ????????//讀取值??
30. ????????NSString?*name?=?[p?valueForKey:@"name"];??
31. ??????????
32. ????????//設(shè)置基本數(shù)據(jù)類型??
33. ????????//這里需要將基本類型轉(zhuǎn)化成NSNumber??
34. ????????//在設(shè)置值的時(shí)候,會(huì)有自動(dòng)解包的過(guò)程,NSNumber會(huì)解包賦值給age??
35. ????????[p?setValue:@22?forKey:@"age"];??
36. ??????????
37. ????????NSLog(@"%@",p);??
38. ??????????
39. ????????return?0;??
40. ????}??
41. ????return?0;??
42. }??
這里我們生成一個(gè)Person對(duì)象,然后開(kāi)始使用KVC技術(shù)了:
1、設(shè)置屬性值
[java]??view plaincopy
1. //設(shè)置值??
2. //這里setValue方法:第一個(gè)參數(shù)是value,第二個(gè)參數(shù)是key(就是類的屬性名稱)??
3. [p?setValue:@"jiangwei"?forKey:@"name"];??
4. ??????????
5. Dog?*dog?=?[[Dog?alloc]?init];??
6. [p?setValue:dog?forKey:@"dog"];??
使用setValue方法,就可以進(jìn)行對(duì)屬性進(jìn)行設(shè)置值操作了,同時(shí)需要傳遞這個(gè)屬性的名稱,這個(gè)和Java中使用反射機(jī)制真的很像。
注:KVC設(shè)置值時(shí),如果屬性有set方法,則優(yōu)先調(diào)用set方法,如果沒(méi)有則直接設(shè)置上去,get方法一樣
[java]??view plaincopy
1. //設(shè)置基本數(shù)據(jù)類型??
2. //這里需要將基本類型轉(zhuǎn)化成NSNumber??
3. //在設(shè)置值的時(shí)候,會(huì)有自動(dòng)解包的過(guò)程,NSNumber會(huì)解包賦值給age??
4. [p?setValue:@22?forKey:@"age"];??
還有一個(gè)需要注意的地方:當(dāng)我們?cè)谠O(shè)置基本類型的時(shí)候,需要將其轉(zhuǎn)化成NSNumber類型的。
2、取屬性的值
[java]??view plaincopy
1. //讀取值??
2. NSString?*name?=?[p?valueForKey:@"name"];??
取值就簡(jiǎn)單了
下面再來(lái)看一下KVC中強(qiáng)大的功能:鍵值路徑
鍵值路徑是對(duì)于一個(gè)類中有數(shù)組對(duì)象的屬性進(jìn)行便捷操作。
看個(gè)場(chǎng)景:
一個(gè)作者有多本書
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. ????//作者出版的書,一個(gè)作者對(duì)應(yīng)多個(gè)書籍對(duì)象??
15. ????NSArray?*_issueBook;??
16. }??
17. ??
18. @end??
作者類中定義了名字和一個(gè)書籍?dāng)?shù)組
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??
定義了一個(gè)作者屬性,書的名字,價(jià)格
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??
看一下測(cè)試代碼
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. ????????//設(shè)置作者?
22. ????????[book?setValue:author?forKey:@"author"];?
23. ?????????
24. ????????//設(shè)置作者的名字?
25. ????????//路徑為:author.name,中間用點(diǎn)號(hào)進(jìn)行連接?
26. ????????[book?setValue:@"jiangwei"?forKeyPath:@"author.name"];?
27. ????????NSString?*name?=?[author?valueForKey:@"name"];?
28. ????????NSLog(@"name?is?%@",name);?
29. ?????????*/??
30. ??????????
31. ??????????
32. ????????//--------------------KVC的運(yùn)算??
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. ????????//基本數(shù)據(jù)類型會(huì)自動(dòng)被包裝成NSNumber,裝到數(shù)組中??
46. ????????//得到所有書籍的價(jià)格??
47. ????????NSArray?*priceArray?=?[author?valueForKeyPath:@"issueBook.price"];??
48. ????????NSLog(@"%@",priceArray);??
49. ??????????
50. ????????//獲取數(shù)組的大小??
51. ????????NSNumber?*count?=?[author?valueForKeyPath:@"issueBook.@count"];??
52. ????????NSLog(@"count=%@",count);??
53. ??????????
54. ????????//獲取書籍價(jià)格的總和??
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. ????????//獲取書籍的價(jià)格最大值和最小值??
63. ????????NSNumber?*max?=?[author?valueForKeyPath:@"issueBook.@max.price"];??
64. ????????NSNumber?*min?=?[author?valueForKeyPath:@"issueBook.@min.price"];??
65. ??????????
66. ????}??
67. ????return?0;??
68. }??
1、首先通過(guò)前面說(shuō)到的KVC設(shè)置作者的書籍?dāng)?shù)組
[objc]??view plaincopy
1. //--------------------KVC的運(yùn)算??
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、下面就開(kāi)始用到KVC中鍵值路徑了
1)獲取作者類中書籍?dāng)?shù)組中所有書籍的價(jià)格
[java]??view plaincopy
1. //基本數(shù)據(jù)類型會(huì)自動(dòng)被包裝成NSNumber,裝到數(shù)組中??
2. //得到所有書籍的價(jià)格??
3. NSArray?*priceArray?=?[author?valueForKeyPath:@"issueBook.price"];??
4. NSLog(@"%@",priceArray);??
看到了:@"issueBook.price" 這就是鍵值路徑的使用,issueBook是作者類中的書籍?dāng)?shù)組屬性名,price是書籍類的屬性,中間用點(diǎn)號(hào)進(jìn)行連接,這樣我們就可以獲取到了所有書籍的價(jià)格了,如果在Java中,我們需要用一個(gè)循環(huán)操作。但是OC中多么方便。
2)獲取作者類中書籍?dāng)?shù)組的大小
[java]??view plaincopy
1. //獲取數(shù)組的大小??
2. NSNumber?*count?=?[author?valueForKeyPath:@"issueBook.@count"];??
3. NSLog(@"count=%@",count);??
使用 @"issueBook.@count" 鍵值路徑獲取書籍?dāng)?shù)組的大小,issueBook是作者類中的書籍?dāng)?shù)組屬性名,@count是特定一個(gè)寫法,可以把它想象成一個(gè)方法,中間任然用點(diǎn)號(hào)進(jìn)行連接
3)獲取作者類中書籍?dāng)?shù)組的價(jià)格總和
[java]??view plaincopy
1. //獲取書籍價(jià)格的總和??
2. NSNumber?*sum?=?[author?valueForKeyPath:@"issueBook.@sum.price"];??
3. NSLog(@"%@",sum);??
使用 @"issueBook.@sum.price" 鍵值路徑獲取書籍?dāng)?shù)組中的價(jià)格總和,issueBook是作者類中的書籍?dāng)?shù)組屬性名,@sum是特性寫法,可以把它想象成一個(gè)方法,price是書籍的價(jià)格屬性名,可以把它看成是@sum的一個(gè)參數(shù),中間用點(diǎn)號(hào)進(jìn)行連接
如果在java中,這個(gè)需要用一個(gè)循環(huán)來(lái)計(jì)算總和,OC中很方便的
4)獲取作者類中書籍?dāng)?shù)組的價(jià)格平均值、最小值、最大值
[objc]??view plaincopy
1. //獲取書籍的平均值??
2. NSNumber?*avg?=?[author?valueForKeyPath:@"issueBook.@avg.price"];??
3. NSLog(@"%@",avg);??
4. ??
5. //獲取書籍的價(jià)格最大值和最小值??
6. NSNumber?*max?=?[author?valueForKeyPath:@"issueBook.@max.price"];??
7. NSNumber?*min?=?[author?valueForKeyPath:@"issueBook.@min.price"];??
操作和上面類似,這里就不解釋了
我們看到上面返回來(lái)的數(shù)據(jù)都是NSNumber類型的
二、KVO操作
KVO操作在OC中也是經(jīng)常會(huì)用到的,而且這種機(jī)制在java中不存在的。
它的作用就是用來(lái)監(jiān)聽(tīng)類中屬性值的變化,實(shí)現(xiàn)原理是觀察者模式,當(dāng)然我們也可以使用觀察者模式在Java中實(shí)現(xiàn)這樣的機(jī)制
看一下具體的例子:現(xiàn)在有一個(gè)小孩類,他有兩個(gè)屬性:開(kāi)心值,饑餓值,然后還有一個(gè)護(hù)士類,用來(lái)監(jiān)聽(tīng)孩子類的這兩個(gè)屬性值的
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. ????????//啟動(dòng)定時(shí)器??
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方法修改屬性值,才能觸發(fā)KVO??
25. ??????
26. ????int?value?=?_hapyValue;??
27. ????[self?setHapyValue:--value];??
28. ??????
29. ????int?values?=?_hurryValue;??
30. ????[self?setHurryValue:--values];??
31. }??
32. ??
33. ??
34. @end??
在初始化方法中,我們啟動(dòng)一個(gè)定時(shí)器,然后隔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??
定義一個(gè)孩子屬性
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為_(kāi)children對(duì)象添加一個(gè)觀察者,用于觀察監(jiān)聽(tīng)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. //觸發(fā)方法??
30. -?(void)observeValueForKeyPath:(NSString?*)keyPath?ofObject:(id)object?change:(NSDictionary?*)change?context:(voidvoid?*)context{??
31. ????NSLog(@"%@",change);??
32. ????//通過(guò)打印change,我們可以看到對(duì)應(yīng)的key??
33. ??????
34. ????//通過(guò)keyPath來(lái)判斷不同屬性的觀察者??
35. ????if([keyPath?isEqualToString:@"hapyValue"]){??
36. ????????//這里change中有old和new的值是因?yàn)槲覀冊(cè)谡{(diào)用addObserver方法時(shí),用到了??
37. ????????//NSKeyValueObservingOptionNew?|?NSKeyValueObservingOptionOld;想要哪一個(gè)就用哪一個(gè)??
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的值是因?yàn)槲覀冊(cè)谡{(diào)用addObserver方法時(shí),用到了??
48. ????????//NSKeyValueObservingOptionNew?|?NSKeyValueObservingOptionOld;想要哪一個(gè)就用哪一個(gè)??
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參數(shù)??
60. ??????
61. ??????
62. ??????
63. ????//使用KVC去修改屬性的值,也會(huì)觸發(fā)事件??
64. }??
65. ??
66. -?(void)dealloc{??
67. ??????
68. ????//移除觀察者??
69. ????[_children?removeObserver:self?forKeyPath:@"hapyValue"];??
70. ????[_children?removeObserver:self?forKeyPath:@"hurryValue"];??
71. ??????
72. }??
73. ??
74. @end??
看到了在這里就開(kāi)始進(jìn)行監(jiān)聽(tīng)操作了
下面來(lái)具體看一下如何做到監(jiān)聽(tīng)的
1、添加監(jiān)聽(tīng)對(duì)象
我們使用addObserver方法給孩子添加監(jiān)聽(tīng)對(duì)象
第一個(gè)參數(shù):監(jiān)聽(tīng)者,這里是Nure,所以可以直接傳遞self
第二個(gè)參數(shù):監(jiān)聽(tīng)對(duì)象的屬性名
第三個(gè)參數(shù):監(jiān)聽(tīng)這個(gè)屬性的狀態(tài):這里可以使用|進(jìn)行多種組合操作,屬性的新值和舊值
第四個(gè)參數(shù):傳遞內(nèi)容給監(jiān)聽(tīng)方法
[java]??view plaincopy
1. //觀察小孩的hapyValue??
2. //使用KVO為_(kāi)children對(duì)象添加一個(gè)觀察者,用于觀察監(jiān)聽(tīng)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、監(jiān)聽(tīng)方法
[objc]??view plaincopy
1. //觸發(fā)方法??
2. -?(void)observeValueForKeyPath:(NSString?*)keyPath?ofObject:(id)object?change:(NSDictionary?*)change?context:(voidvoid?*)context{??
3. ????NSLog(@"%@",change);??
4. ????//通過(guò)打印change,我們可以看到對(duì)應(yīng)的key??
5. ??????
6. ????//通過(guò)keyPath來(lái)判斷不同屬性的觀察者??
7. ????if([keyPath?isEqualToString:@"hapyValue"]){??
8. ????????//這里change中有old和new的值是因?yàn)槲覀冊(cè)谡{(diào)用addObserver方法時(shí),用到了??
9. ????????//NSKeyValueObservingOptionNew?|?NSKeyValueObservingOptionOld;想要哪一個(gè)就用哪一個(gè)??
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的值是因?yàn)槲覀冊(cè)谡{(diào)用addObserver方法時(shí),用到了??
20. ????????//NSKeyValueObservingOptionNew?|?NSKeyValueObservingOptionOld;想要哪一個(gè)就用哪一個(gè)??
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參數(shù)??
32. ??????
33. ??????
34. ??????
35. ????//使用KVC去修改屬性的值,也會(huì)觸發(fā)事件??
36. }??
我們上面?zhèn)鬟f的第一個(gè)參數(shù)是監(jiān)聽(tīng)者,這個(gè)方法也是在監(jiān)聽(tīng)者中實(shí)現(xiàn)的,當(dāng)屬性值發(fā)生變化的時(shí)候,這個(gè)方法會(huì)被回調(diào)
這個(gè)方法的參數(shù):
第一個(gè)參數(shù):鍵值路徑
第二個(gè)參數(shù):監(jiān)聽(tīng)對(duì)象
第三個(gè)參數(shù):變化的值
第四個(gè)參數(shù):傳遞的內(nèi)容
我們看到代碼中有一個(gè)特殊的參數(shù):第三個(gè)參數(shù):NSDirctionary類型的
其實(shí)我們?nèi)绻恢朗歉墒裁吹?#xff0c;我們可以打印一下他的結(jié)果看一下,很簡(jiǎn)單,這里就不截圖說(shuō)明了
我們會(huì)發(fā)現(xiàn)他有兩個(gè)鍵值對(duì)
key是:new和old
他們就是分別代表這個(gè)屬性值變化的前后值,同時(shí)他們的得到也和之前我們添加監(jiān)聽(tīng)對(duì)象時(shí)設(shè)置的第三個(gè)參數(shù)有關(guān):
NSKeyValueObservingOptionNew?|NSKeyValueObservingOptionOld
那個(gè)地方設(shè)置了幾種狀態(tài),這里的NSDirctionary中就會(huì)有幾個(gè)鍵值對(duì)
3、銷毀方法
這個(gè)并不屬于KVO的內(nèi)容了,只是在這里用到了就順便說(shuō)一下
[objc]??view plaincopy
1. -?(void)dealloc{??
2. ??????
3. ????//移除觀察者??
4. ????[_children?removeObserver:self?forKeyPath:@"hapyValue"];??
5. ????[_children?removeObserver:self?forKeyPath:@"hurryValue"];??
6. ??????
7. }??
我們?cè)趧?chuàng)建一個(gè)對(duì)象的時(shí)候會(huì)調(diào)用alloc方法,當(dāng)對(duì)象被銷毀的時(shí)候會(huì)調(diào)用dealloc這個(gè)方法,這個(gè)和C++中的析構(gòu)函數(shù)一樣,Java中有垃圾回收器,所以沒(méi)有此類的方法,但是有一個(gè)finalize方法,其實(shí)這個(gè)方法就是在垃圾回收器回收對(duì)象的時(shí)候會(huì)調(diào)用,和這個(gè)功能差不多,但是在Java中,我們并不提倡使用這個(gè)方法。因?yàn)闀?huì)造成GC的回收發(fā)生錯(cuò)誤。
我們?cè)阡N毀方法中需要移除監(jiān)聽(tīng)者
總結(jié)
這一篇就介紹了OC中比較有特色的兩個(gè)機(jī)制:KVC和KVO
KVC:就是可以暴力的去get/set類的私有屬性,同時(shí)還有強(qiáng)大的鍵值路徑對(duì)數(shù)組類型的屬性進(jìn)行操作 KVO:監(jiān)聽(tīng)類中屬性值變化的
轉(zhuǎn)載于:https://www.cnblogs.com/GhostKZShadow/p/5105176.html
總結(jié)
- 上一篇: 千元以下家用投影如何样?值得买吗?
- 下一篇: springmvc学习笔记--mybat