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和KVO
KVC:就是可以暴力的去get/set類的私有屬性,同時還有強大的鍵值路徑對數組類型的屬性進行操作
一、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和KVO
KVC:就是可以暴力的去get/set類的私有屬性,同時還有強大的鍵值路徑對數組類型的屬性進行操作
KVO:監聽類中屬性值變化的