KVO全稱KeyValueObserving
,俗稱鍵值監聽,是蘋果提供的一套事件通知機制。容許對象監聽另外一個對象特定屬性的改變,並在改變時接收到事件。因爲KVO的實現機制,因此對屬性纔會發生做用,通常繼承自NSObject
的對象都默認支持KVO。編程
@interface YZPerson : NSObject
@property (nonatomic,assign) int age;
@property (nonatomic,strong) NSString *name;
@end
複製代碼
- (void)viewDidLoad {
[super viewDidLoad];
self.person = [[YZPerson alloc] init];
// 註冊觀察者
NSKeyValueObservingOptions options = NSKeyValueObservingOptionNew | NSKeyValueObservingOptionOld;
[self.person addObserver:self forKeyPath:@"name" options:options context:@"1111"];
}
// 回調方法。當監聽對象的屬性值發生改變時,就會調用
- (void)observeValueForKeyPath:(NSString *)keyPath ofObject:(id)object change:(NSDictionary *)change context:(void *)context
{
NSLog(@"監聽到%@的%@屬性值改變了 - %@ - %@", object, keyPath, change, context);
}
-(void)dealloc{
// 移除監聽
[self.person removeObserver:self forKeyPath:@"name"];
}
複製代碼
注意:重複移除監聽會崩潰,由於已經移除了,找不到了。因此,要保證add和remove是成對出現的。markdown
KVO能夠監聽單個屬性的變化,也能夠監聽集合對象的變化。 經過KVC的mutableArrayValueForKey:
等方法得到代理對象,當代理對象的內部對象發生改變時,會回調KVO監聽的方法。集合對象包含NSArray
和NSSet
。函數
KVO是經過isa-swizzling技術實現的。編碼
1.在運行時Runtime根據原類建立一箇中間類NSKVONotifying_xxx
,這個中間類是原類的子類,並動態修改當前 對象 的isa
指向中間類。 2.當修改 對象的屬性時,會調用 _NSSetXXXValueAndNotify
函數 。 該函數裏面會先調用willChangeValueForKey:
,而後調用父類原來的 setter
方法修改值,最後是 didChangeValueForKey:
,它的內部會觸發監聽器(Oberser)
的監聽方法observeValueForKeyPath:ofObject:change:context:
,而且將class方法重寫,返回原類的Class。atom
對同一個類的不一樣對象進行KVO,由於動態指向了各自的中間類,它們的類對象不一樣。因此能夠準確監聽不一樣對象的特定屬性。 由[instance class]
獲得的類名是同樣的(即instance
所屬的類),而不是中間類的名字。spa
當改變屬性的時候,是經過調用它的setter進行的。添加KVO監聽以後,setter 指向了 _NSSetObjectValueAndNotify
函數。 若是沒有經過 setter 來改變屬性值,或者沒有屬性沒有對應的setter方法,則不會觸發KVO。代理
手動調用對象的willChangeValueForKey、didChangeValueForKey
兩個方法,也會觸發監聽回調方法,可是屬性值不變。由於沒有給屬性賦值。code
[self.person willChangeValueForKey:@"name"];
[self.person didChangeValueForKey:@"name"];
複製代碼
KVC(鍵值編碼),即 Key-Value Coding
,一個非正式的 Protocol
,使用字符串(鍵)訪問一個對象實例變量的機制。而不是經過調用 setter、getter
方法等顯式的存取方式去訪問。orm
KVC和KVO都屬於鍵值編程,並且底層實現機制都是isa-swizzing。server
KVO和NSNotificationCenter都是iOS中觀察者模式的一種實現。 二者都是一對多,可是對象之間直接的交互,notification 明顯得多,須要notificationCenter 來作爲中間交互。 notification 的優勢是,監聽不侷限於對屬性,還能夠對多種多樣的狀態變化進行監聽,監聽範圍廣。
KVO對被監聽對象無侵入性,不須要修改其內部代碼便可實現監聽。
(系統默認是不容許修改的)
[self.pageControl setValue:currentImage forKey:@"_currentPageImage"];
[self.pageControl setValue:pageImage forKey:@"_pageImage"];
複製代碼
通常狀況下只有經過調用 set 方法對值進行改變纔會觸發 KVO。可是在調用NSMutableArray
的 addObject
或removeObject
系列方法時,並不會觸發它的 set 方法。 爲了實現NSMutableArray
的 KVO,官方爲咱們提供了以下方法:
@property (nonatomic, strong) NSMutableArray *arr;
//添加元素操做
[[self mutableArrayValueForKey:@"arr"] addObject:item];
//移除元素操做
[[self mutableArrayValueForKey:@"arr"] removeObjectAtIndex:0];
複製代碼